Path: blob/master/thirdparty/basis_universal/encoder/basisu_uastc_hdr_4x4_enc.cpp
9902 views
// basisu_uastc_hdr_4x4_enc.cpp1#include "basisu_uastc_hdr_4x4_enc.h"2#include "../transcoder/basisu_transcoder.h"34using namespace basist;56namespace basisu7{89const uint32_t UHDR_MODE11_FIRST_ISE_RANGE = astc_helpers::BISE_3_LEVELS, UHDR_MODE11_LAST_ISE_RANGE = astc_helpers::BISE_16_LEVELS;10const uint32_t UHDR_MODE7_PART1_FIRST_ISE_RANGE = astc_helpers::BISE_3_LEVELS, UHDR_MODE7_PART1_LAST_ISE_RANGE = astc_helpers::BISE_16_LEVELS;11const uint32_t UHDR_MODE7_PART2_FIRST_ISE_RANGE = astc_helpers::BISE_3_LEVELS, UHDR_MODE7_PART2_LAST_ISE_RANGE = astc_helpers::BISE_8_LEVELS;12const uint32_t UHDR_MODE11_PART2_FIRST_ISE_RANGE = astc_helpers::BISE_3_LEVELS, UHDR_MODE11_PART2_LAST_ISE_RANGE = astc_helpers::BISE_4_LEVELS;1314uastc_hdr_4x4_codec_options::uastc_hdr_4x4_codec_options() :15astc_hdr_codec_base_options()16{17init();18}1920void uastc_hdr_4x4_codec_options::init()21{22astc_hdr_codec_base_options::init();2324// This was the log bias we used on the initial release. It's too low.25//m_q_log_bias = Q_LOG_BIAS_4x4;2627m_q_log_bias = Q_LOG_BIAS_6x6;2829m_bc6h_err_weight = .85f;3031#if 032// HACK HACK33m_disable_weight_plane_optimization = true;34m_take_first_non_clamping_mode11_submode = false;35m_take_first_non_clamping_mode7_submode = false;36#endif3738// Must set the quality level at least once to reset this struct.39set_quality_level(cDefaultLevel);40}4142void uastc_hdr_4x4_codec_options::set_quality_best()43{44// highest achievable quality45m_mode11_direct_only = false;4647m_use_solid = true;4849m_use_mode11_part1 = true;50m_mode11_uber_mode = true;51m_first_mode11_weight_ise_range = UHDR_MODE11_FIRST_ISE_RANGE;52m_last_mode11_weight_ise_range = UHDR_MODE11_LAST_ISE_RANGE;53m_first_mode11_submode = -1;54m_last_mode11_submode = 7;5556m_use_mode7_part1 = true;57m_first_mode7_part1_weight_ise_range = UHDR_MODE7_PART1_FIRST_ISE_RANGE;58m_last_mode7_part1_weight_ise_range = UHDR_MODE7_PART1_LAST_ISE_RANGE;59m_mode7_full_s_optimization = true;6061m_use_mode7_part2 = true;62m_mode7_part2_part_masks = UINT32_MAX;63m_first_mode7_part2_weight_ise_range = UHDR_MODE7_PART2_FIRST_ISE_RANGE;64m_last_mode7_part2_weight_ise_range = UHDR_MODE7_PART2_LAST_ISE_RANGE;6566m_use_mode11_part2 = true;67m_mode11_part2_part_masks = UINT32_MAX;68m_first_mode11_part2_weight_ise_range = UHDR_MODE11_PART2_FIRST_ISE_RANGE;69m_last_mode11_part2_weight_ise_range = UHDR_MODE11_PART2_LAST_ISE_RANGE;7071m_refine_weights = true;7273m_use_estimated_partitions = false;74m_max_estimated_partitions = 0;75}7677void uastc_hdr_4x4_codec_options::set_quality_normal()78{79m_use_solid = true;8081// We'll allow uber mode in normal if the user allows it.82m_use_mode11_part1 = true;83m_mode11_uber_mode = true;84m_first_mode11_weight_ise_range = 6;85m_last_mode11_weight_ise_range = UHDR_MODE11_LAST_ISE_RANGE;8687m_use_mode7_part1 = true;88m_first_mode7_part1_weight_ise_range = UHDR_MODE7_PART1_LAST_ISE_RANGE;89m_last_mode7_part1_weight_ise_range = UHDR_MODE7_PART1_LAST_ISE_RANGE;9091m_use_mode7_part2 = true;92m_mode7_part2_part_masks = UINT32_MAX;93m_first_mode7_part2_weight_ise_range = UHDR_MODE7_PART2_LAST_ISE_RANGE;94m_last_mode7_part2_weight_ise_range = UHDR_MODE7_PART2_LAST_ISE_RANGE;9596m_use_mode11_part2 = true;97m_mode11_part2_part_masks = UINT32_MAX;98m_first_mode11_part2_weight_ise_range = UHDR_MODE11_PART2_LAST_ISE_RANGE;99m_last_mode11_part2_weight_ise_range = UHDR_MODE11_PART2_LAST_ISE_RANGE;100101m_refine_weights = true;102}103104void uastc_hdr_4x4_codec_options::set_quality_fastest()105{106m_use_solid = true;107108m_use_mode11_part1 = true;109m_mode11_uber_mode = false;110m_first_mode11_weight_ise_range = UHDR_MODE11_LAST_ISE_RANGE;111m_last_mode11_weight_ise_range = UHDR_MODE11_LAST_ISE_RANGE;112113m_use_mode7_part1 = false;114m_mode7_full_s_optimization = false;115116m_use_mode7_part2 = false;117m_use_mode11_part2 = false;118119m_refine_weights = false;120}121122void uastc_hdr_4x4_codec_options::set_quality_level(int level)123{124level = clamp(level, cMinLevel, cMaxLevel);125126m_level = level;127128// First ensure all options are set to best.129set_quality_best();130131switch (level)132{133case 0:134{135set_quality_fastest();136break;137}138case 1:139{140set_quality_normal();141142m_first_mode11_weight_ise_range = UHDR_MODE11_LAST_ISE_RANGE - 1;143m_last_mode11_weight_ise_range = UHDR_MODE11_LAST_ISE_RANGE;144145m_use_mode7_part1 = false;146m_mode7_full_s_optimization = false;147m_use_mode7_part2 = false;148149m_use_estimated_partitions = true;150m_max_estimated_partitions = 1;151152m_mode11_part2_part_masks = 1 | 2;153m_mode7_part2_part_masks = 1 | 2;154155// TODO: Disabling this hurts BC6H quality, but significantly speeds up compression.156//m_refine_weights = false;157break;158}159case 2:160{161set_quality_normal();162163m_use_estimated_partitions = true;164m_max_estimated_partitions = 2;165166m_mode11_part2_part_masks = 1 | 2;167m_mode7_part2_part_masks = 1 | 2;168169break;170}171case 3:172{173m_use_estimated_partitions = true;174m_max_estimated_partitions = 2;175176m_mode11_part2_part_masks = 1 | 2 | 4 | 8;177m_mode7_part2_part_masks = 1 | 2 | 4 | 8;178179break;180}181default:182{183// best options already set184break;185}186}187}188189//--------------------------------------------------------------------------------------------------------------------------190191static bool pack_solid(const vec4F* pBlock_linear_colors, basisu::vector<astc_hdr_4x4_pack_results>& all_results, const uastc_hdr_4x4_codec_options& coptions)192{193float r = 0.0f, g = 0.0f, b = 0.0f;194195const float LOG_BIAS = .125f;196197bool solid_block = true;198for (uint32_t i = 0; i < 16; i++)199{200if ((pBlock_linear_colors[0][0] != pBlock_linear_colors[i][0]) ||201(pBlock_linear_colors[0][1] != pBlock_linear_colors[i][1]) ||202(pBlock_linear_colors[0][2] != pBlock_linear_colors[i][2]))203{204solid_block = false;205}206207r += log2f(pBlock_linear_colors[i][0] + LOG_BIAS);208g += log2f(pBlock_linear_colors[i][1] + LOG_BIAS);209b += log2f(pBlock_linear_colors[i][2] + LOG_BIAS);210}211212if (solid_block)213{214r = pBlock_linear_colors[0][0];215g = pBlock_linear_colors[0][1];216b = pBlock_linear_colors[0][2];217}218else219{220r = maximum<float>(0.0f, powf(2.0f, r * (1.0f / 16.0f)) - LOG_BIAS);221g = maximum<float>(0.0f, powf(2.0f, g * (1.0f / 16.0f)) - LOG_BIAS);222b = maximum<float>(0.0f, powf(2.0f, b * (1.0f / 16.0f)) - LOG_BIAS);223224// for safety225r = minimum<float>(r, MAX_HALF_FLOAT);226g = minimum<float>(g, MAX_HALF_FLOAT);227b = minimum<float>(b, MAX_HALF_FLOAT);228}229230half_float rh = float_to_half_non_neg_no_nan_inf(r), gh = float_to_half_non_neg_no_nan_inf(g), bh = float_to_half_non_neg_no_nan_inf(b), ah = float_to_half_non_neg_no_nan_inf(1.0f);231232astc_hdr_4x4_pack_results results;233results.clear();234235uint8_t* packed_blk = (uint8_t*)&results.m_solid_blk;236results.m_is_solid = true;237238packed_blk[0] = 0b11111100;239packed_blk[1] = 255;240packed_blk[2] = 255;241packed_blk[3] = 255;242packed_blk[4] = 255;243packed_blk[5] = 255;244packed_blk[6] = 255;245packed_blk[7] = 255;246247packed_blk[8] = (uint8_t)rh;248packed_blk[9] = (uint8_t)(rh >> 8);249packed_blk[10] = (uint8_t)gh;250packed_blk[11] = (uint8_t)(gh >> 8);251packed_blk[12] = (uint8_t)bh;252packed_blk[13] = (uint8_t)(bh >> 8);253packed_blk[14] = (uint8_t)ah;254packed_blk[15] = (uint8_t)(ah >> 8);255256results.m_best_block_error = 0;257258if (!solid_block)259{260const float R_WEIGHT = coptions.m_r_err_scale;261const float G_WEIGHT = coptions.m_g_err_scale;262263// This MUST match how errors are computed in eval_selectors().264for (uint32_t i = 0; i < 16; i++)265{266half_float dr = float_to_half_non_neg_no_nan_inf(pBlock_linear_colors[i][0]), dg = float_to_half_non_neg_no_nan_inf(pBlock_linear_colors[i][1]), db = float_to_half_non_neg_no_nan_inf(pBlock_linear_colors[i][2]);267double rd = q(rh, Q_LOG_BIAS_4x4) - q(dr, Q_LOG_BIAS_4x4);268double gd = q(gh, Q_LOG_BIAS_4x4) - q(dg, Q_LOG_BIAS_4x4);269double bd = q(bh, Q_LOG_BIAS_4x4) - q(db, Q_LOG_BIAS_4x4);270271double e = R_WEIGHT * (rd * rd) + G_WEIGHT * (gd * gd) + bd * bd;272273results.m_best_block_error += e;274}275}276277const half_float hc[3] = { rh, gh, bh };278279bc6h_enc_block_solid_color(&results.m_bc6h_block, hc);280281all_results.push_back(results);282283return solid_block;284}285286//--------------------------------------------------------------------------------------------------------------------------287288static void pack_mode11(289const vec4F* pBlock_linear_colors, const half_float pBlock_pixels_half[16][3], const vec4F pBlock_pixels_q16[16],290basisu::vector<astc_hdr_4x4_pack_results>& all_results,291const uastc_hdr_4x4_codec_options& coptions,292uint32_t first_weight_ise_range, uint32_t last_weight_ise_range, bool constrain_ise_weight_selectors)293{294BASISU_NOTE_UNUSED(pBlock_linear_colors);295assert(first_weight_ise_range <= last_weight_ise_range);296297uint8_t trial_endpoints[NUM_MODE11_ENDPOINTS], trial_weights[16];298uint32_t trial_submode11 = 0;299300clear_obj(trial_endpoints);301clear_obj(trial_weights);302303for (uint32_t weight_ise_range = first_weight_ise_range; weight_ise_range <= last_weight_ise_range; weight_ise_range++)304{305const bool direct_only = coptions.m_mode11_direct_only;306307uint32_t endpoint_ise_range = astc_helpers::BISE_256_LEVELS;308if (weight_ise_range == astc_helpers::BISE_16_LEVELS)309endpoint_ise_range = astc_helpers::BISE_192_LEVELS;310else311{312assert(weight_ise_range < astc_helpers::BISE_16_LEVELS);313}314315double trial_error = encode_astc_hdr_block_mode_11(16, pBlock_pixels_half, pBlock_pixels_q16, weight_ise_range, trial_submode11, BIG_FLOAT_VAL, trial_endpoints, trial_weights, coptions, direct_only,316endpoint_ise_range, coptions.m_mode11_uber_mode && (weight_ise_range >= astc_helpers::BISE_4_LEVELS) && coptions.m_allow_uber_mode, constrain_ise_weight_selectors, coptions.m_first_mode11_submode, coptions.m_last_mode11_submode, false, cOrdinaryLeastSquares);317318if (trial_error < BIG_FLOAT_VAL)319{320astc_hdr_4x4_pack_results results;321results.clear();322323results.m_best_block_error = trial_error;324325results.m_best_submodes[0] = trial_submode11;326results.m_constrained_weights = constrain_ise_weight_selectors;327328results.m_best_blk.m_num_partitions = 1;329results.m_best_blk.m_color_endpoint_modes[0] = 11;330results.m_best_blk.m_weight_ise_range = (uint8_t)weight_ise_range;331results.m_best_blk.m_endpoint_ise_range = (uint8_t)endpoint_ise_range;332333memcpy(results.m_best_blk.m_endpoints, trial_endpoints, NUM_MODE11_ENDPOINTS);334memcpy(results.m_best_blk.m_weights, trial_weights, 16);335336#ifdef _DEBUG337// Sanity checking338{339half_float block_pixels_half[16][3];340341for (uint32_t i = 0; i < 16; i++)342{343block_pixels_half[i][0] = float_to_half_non_neg_no_nan_inf(pBlock_linear_colors[i][0]);344block_pixels_half[i][1] = float_to_half_non_neg_no_nan_inf(pBlock_linear_colors[i][1]);345block_pixels_half[i][2] = float_to_half_non_neg_no_nan_inf(pBlock_linear_colors[i][2]);346}347348half_float unpacked_astc_blk_rgba[4][4][4];349bool res = astc_helpers::decode_block(results.m_best_blk, unpacked_astc_blk_rgba, 4, 4, astc_helpers::cDecodeModeHDR16);350assert(res);351352half_float unpacked_astc_blk_rgb[4][4][3];353for (uint32_t y = 0; y < 4; y++)354for (uint32_t x = 0; x < 4; x++)355for (uint32_t c = 0; c < 3; c++)356unpacked_astc_blk_rgb[y][x][c] = unpacked_astc_blk_rgba[y][x][c];357358double cmp_err = compute_block_error(16, &block_pixels_half[0][0], &unpacked_astc_blk_rgb[0][0][0], coptions);359assert(results.m_best_block_error == cmp_err);360}361#endif362363// transcode to BC6H364assert(results.m_best_blk.m_color_endpoint_modes[0] == 11);365366// Get qlog12 endpoints367int e[2][3];368bool success = decode_mode11_to_qlog12(results.m_best_blk.m_endpoints, e, results.m_best_blk.m_endpoint_ise_range);369assert(success);370BASISU_NOTE_UNUSED(success);371372// Transform endpoints to half float373half_float h_e[3][2] =374{375{ qlog_to_half(e[0][0], 12), qlog_to_half(e[1][0], 12) },376{ qlog_to_half(e[0][1], 12), qlog_to_half(e[1][1], 12) },377{ qlog_to_half(e[0][2], 12), qlog_to_half(e[1][2], 12) }378};379380// Transcode to bc6h381success = transcode_bc6h_1subset(h_e, results.m_best_blk, results.m_bc6h_block);382assert(success);383384all_results.push_back(results);385}386}387}388389//--------------------------------------------------------------------------------------------------------------------------390391static void pack_mode7_single_part(392const half_float pBlock_pixels_half[16][3], const vec4F pBlock_pixels_q16[16],393basisu::vector<astc_hdr_4x4_pack_results>& all_results, const uastc_hdr_4x4_codec_options& coptions,394uint32_t first_mode7_part1_weight_ise_range, uint32_t last_mode7_part1_weight_ise_range)395{396assert(first_mode7_part1_weight_ise_range <= last_mode7_part1_weight_ise_range);397398uint8_t trial_endpoints[NUM_MODE7_ENDPOINTS], trial_weights[16];399uint32_t trial_submode7 = 0;400401clear_obj(trial_endpoints);402clear_obj(trial_weights);403404for (uint32_t weight_ise_range = first_mode7_part1_weight_ise_range; weight_ise_range <= last_mode7_part1_weight_ise_range; weight_ise_range++)405{406const uint32_t ise_endpoint_range = astc_helpers::BISE_256_LEVELS;407408double trial_error = encode_astc_hdr_block_mode_7(16, pBlock_pixels_half, pBlock_pixels_q16, weight_ise_range, trial_submode7, BIG_FLOAT_VAL, trial_endpoints, trial_weights, coptions, ise_endpoint_range);409410if (trial_error < BIG_FLOAT_VAL)411{412astc_hdr_4x4_pack_results results;413results.clear();414415results.m_best_block_error = trial_error;416417results.m_best_submodes[0] = trial_submode7;418419results.m_best_blk.m_num_partitions = 1;420results.m_best_blk.m_color_endpoint_modes[0] = 7;421results.m_best_blk.m_weight_ise_range = (uint8_t)weight_ise_range;422results.m_best_blk.m_endpoint_ise_range = (uint8_t)ise_endpoint_range;423424memcpy(results.m_best_blk.m_endpoints, trial_endpoints, NUM_MODE7_ENDPOINTS);425memcpy(results.m_best_blk.m_weights, trial_weights, 16);426427// transcode to BC6H428assert(results.m_best_blk.m_color_endpoint_modes[0] == 7);429430// Get qlog12 endpoints431int e[2][3];432if (!decode_mode7_to_qlog12(results.m_best_blk.m_endpoints, e, nullptr, results.m_best_blk.m_endpoint_ise_range))433continue;434435// Transform endpoints to half float436half_float h_e[3][2] =437{438{ qlog_to_half(e[0][0], 12), qlog_to_half(e[1][0], 12) },439{ qlog_to_half(e[0][1], 12), qlog_to_half(e[1][1], 12) },440{ qlog_to_half(e[0][2], 12), qlog_to_half(e[1][2], 12) }441};442443// Transcode to bc6h444bool status = transcode_bc6h_1subset(h_e, results.m_best_blk, results.m_bc6h_block);445assert(status);446(void)status;447448all_results.push_back(results);449}450}451}452453//--------------------------------------------------------------------------------------------------------------------------454455static bool estimate_partition(456const half_float pBlock_pixels_half[16][3],457int* pBest_parts, uint32_t num_best_parts)458{459assert(num_best_parts <= basist::TOTAL_ASTC_BC6H_COMMON_PARTITIONS2);460461vec3F training_vecs[16], mean(0.0f);462463for (uint32_t i = 0; i < 16; i++)464{465vec3F& v = training_vecs[i];466467v[0] = (float)pBlock_pixels_half[i][0];468v[1] = (float)pBlock_pixels_half[i][1];469v[2] = (float)pBlock_pixels_half[i][2];470471mean += v;472}473mean *= (1.0f / 16.0f);474475vec3F cluster_centroids[2] = { mean - vec3F(.1f), mean + vec3F(.1f) };476477uint32_t cluster_pixels[2][16];478uint32_t num_cluster_pixels[2];479vec3F new_cluster_means[2];480481for (uint32_t s = 0; s < 4; s++)482{483num_cluster_pixels[0] = 0;484num_cluster_pixels[1] = 0;485486new_cluster_means[0].clear();487new_cluster_means[1].clear();488489for (uint32_t i = 0; i < 16; i++)490{491float d0 = training_vecs[i].squared_distance(cluster_centroids[0]);492float d1 = training_vecs[i].squared_distance(cluster_centroids[1]);493494if (d0 < d1)495{496cluster_pixels[0][num_cluster_pixels[0]] = i;497new_cluster_means[0] += training_vecs[i];498num_cluster_pixels[0]++;499}500else501{502cluster_pixels[1][num_cluster_pixels[1]] = i;503new_cluster_means[1] += training_vecs[i];504num_cluster_pixels[1]++;505}506}507508if (!num_cluster_pixels[0] || !num_cluster_pixels[1])509return false;510511cluster_centroids[0] = new_cluster_means[0] / (float)num_cluster_pixels[0];512cluster_centroids[1] = new_cluster_means[1] / (float)num_cluster_pixels[1];513}514515int desired_parts[4][4]; // [y][x]516for (uint32_t p = 0; p < 2; p++)517{518for (uint32_t i = 0; i < num_cluster_pixels[p]; i++)519{520const uint32_t pix_index = cluster_pixels[p][i];521522desired_parts[pix_index >> 2][pix_index & 3] = p;523}524}525526uint32_t part_similarity[basist::TOTAL_ASTC_BC6H_COMMON_PARTITIONS2];527528for (uint32_t part_index = 0; part_index < basist::TOTAL_ASTC_BC6H_COMMON_PARTITIONS2; part_index++)529{530const uint32_t bc7_pattern = basist::g_astc_bc7_common_partitions2[part_index].m_bc7;531532int total_sim_non_inv = 0;533int total_sim_inv = 0;534535for (uint32_t y = 0; y < 4; y++)536{537for (uint32_t x = 0; x < 4; x++)538{539int part = basist::g_bc7_partition2[16 * bc7_pattern + x + y * 4];540541if (part == desired_parts[y][x])542total_sim_non_inv++;543544if ((part ^ 1) == desired_parts[y][x])545total_sim_inv++;546}547}548549int total_sim = maximum(total_sim_non_inv, total_sim_inv);550551part_similarity[part_index] = (total_sim << 8) | part_index;552553} // part_index;554555std::sort(part_similarity, part_similarity + basist::TOTAL_ASTC_BC6H_COMMON_PARTITIONS2);556557for (uint32_t i = 0; i < num_best_parts; i++)558pBest_parts[i] = part_similarity[(basist::TOTAL_ASTC_BC6H_COMMON_PARTITIONS2 - 1) - i] & 0xFF;559560return true;561}562563//--------------------------------------------------------------------------------------------------------------------------564565static void pack_mode7_2part(566const half_float pBlock_pixels_half[16][3], const vec4F pBlock_pixels_q16[16],567basisu::vector<astc_hdr_4x4_pack_results>& all_results, const uastc_hdr_4x4_codec_options& coptions,568int num_estimated_partitions, const int *pEstimated_partitions,569uint32_t first_weight_ise_range, uint32_t last_weight_ise_range)570{571assert(coptions.m_mode7_part2_part_masks);572573astc_helpers::log_astc_block trial_blk;574clear_obj(trial_blk);575trial_blk.m_grid_width = 4;576trial_blk.m_grid_height = 4;577578trial_blk.m_num_partitions = 2;579trial_blk.m_color_endpoint_modes[0] = 7;580trial_blk.m_color_endpoint_modes[1] = 7;581582uint32_t first_part_index = 0, last_part_index = basist::TOTAL_ASTC_BC6H_COMMON_PARTITIONS2;583584if (num_estimated_partitions)585{586first_part_index = 0;587last_part_index = num_estimated_partitions;588}589590for (uint32_t part_index_iter = first_part_index; part_index_iter < last_part_index; ++part_index_iter)591{592uint32_t part_index;593if (num_estimated_partitions)594{595part_index = pEstimated_partitions[part_index_iter];596assert(part_index < basist::TOTAL_ASTC_BC6H_COMMON_PARTITIONS2);597}598else599{600part_index = part_index_iter;601if (((1U << part_index) & coptions.m_mode7_part2_part_masks) == 0)602continue;603}604605const uint32_t astc_pattern = basist::g_astc_bc7_common_partitions2[part_index].m_astc;606const uint32_t bc7_pattern = basist::g_astc_bc7_common_partitions2[part_index].m_bc7;607const bool invert_flag = basist::g_astc_bc7_common_partitions2[part_index].m_invert;608609half_float part_pixels_half[2][16][3];610vec4F part_pixels_q16[2][16];611612uint32_t pixel_part_index[4][4]; // [y][x]613uint32_t num_part_pixels[2] = { 0, 0 };614615// Extract each subset's texels for this partition pattern616for (uint32_t y = 0; y < 4; y++)617{618for (uint32_t x = 0; x < 4; x++)619{620uint32_t part = basist::g_bc7_partition2[16 * bc7_pattern + x + y * 4];621if (invert_flag)622part = 1 - part;623624pixel_part_index[y][x] = part;625626const uint32_t n = num_part_pixels[part];627628part_pixels_half[part][n][0] = pBlock_pixels_half[x + y * 4][0];629part_pixels_half[part][n][1] = pBlock_pixels_half[x + y * 4][1];630part_pixels_half[part][n][2] = pBlock_pixels_half[x + y * 4][2];631part_pixels_q16[part][n] = pBlock_pixels_q16[x + y * 4];632633num_part_pixels[part] = n + 1;634}635}636637trial_blk.m_partition_id = (uint16_t)astc_pattern;638639for (uint32_t weight_ise_range = first_weight_ise_range; weight_ise_range <= last_weight_ise_range; weight_ise_range++)640{641assert(weight_ise_range <= astc_helpers::BISE_8_LEVELS);642643uint32_t ise_endpoint_range = astc_helpers::BISE_256_LEVELS;644if (weight_ise_range == astc_helpers::BISE_5_LEVELS)645ise_endpoint_range = astc_helpers::BISE_192_LEVELS;646else if (weight_ise_range == astc_helpers::BISE_6_LEVELS)647ise_endpoint_range = astc_helpers::BISE_128_LEVELS;648else if (weight_ise_range == astc_helpers::BISE_8_LEVELS)649ise_endpoint_range = astc_helpers::BISE_80_LEVELS;650651uint8_t trial_endpoints[2][NUM_MODE7_ENDPOINTS], trial_weights[2][16];652uint32_t trial_submode7[2];653654clear_obj(trial_endpoints);655clear_obj(trial_weights);656clear_obj(trial_submode7);657658double total_trial_err = 0;659for (uint32_t pack_part_index = 0; pack_part_index < 2; pack_part_index++)660{661total_trial_err += encode_astc_hdr_block_mode_7(662num_part_pixels[pack_part_index], part_pixels_half[pack_part_index], part_pixels_q16[pack_part_index],663weight_ise_range, trial_submode7[pack_part_index], BIG_FLOAT_VAL,664&trial_endpoints[pack_part_index][0], &trial_weights[pack_part_index][0], coptions, ise_endpoint_range);665666} // pack_part_index667668if (total_trial_err < BIG_FLOAT_VAL)669{670trial_blk.m_weight_ise_range = (uint8_t)weight_ise_range;671trial_blk.m_endpoint_ise_range = (uint8_t)ise_endpoint_range;672673for (uint32_t pack_part_index = 0; pack_part_index < 2; pack_part_index++)674memcpy(&trial_blk.m_endpoints[pack_part_index * NUM_MODE7_ENDPOINTS], &trial_endpoints[pack_part_index][0], NUM_MODE7_ENDPOINTS);675676uint32_t src_pixel_index[2] = { 0, 0 };677for (uint32_t y = 0; y < 4; y++)678{679for (uint32_t x = 0; x < 4; x++)680{681uint32_t p = pixel_part_index[y][x];682trial_blk.m_weights[x + y * 4] = trial_weights[p][src_pixel_index[p]++];683}684}685686astc_hdr_4x4_pack_results results;687results.clear();688689results.m_best_block_error = total_trial_err;690results.m_best_submodes[0] = trial_submode7[0];691results.m_best_submodes[1] = trial_submode7[1];692results.m_best_pat_index = part_index;693694results.m_best_blk = trial_blk;695696bool status = transcode_bc6h_2subsets(part_index, results.m_best_blk, results.m_bc6h_block);697assert(status);698BASISU_NOTE_UNUSED(status);699700all_results.push_back(results);701}702703} // weight_ise_range704705} // part_index706}707708//--------------------------------------------------------------------------------------------------------------------------709710static void pack_mode11_2part(711const half_float pBlock_pixels_half[16][3], const vec4F pBlock_pixels_q16[16],712basisu::vector<astc_hdr_4x4_pack_results>& all_results, const uastc_hdr_4x4_codec_options& coptions,713int num_estimated_partitions, const int* pEstimated_partitions)714{715assert(coptions.m_mode11_part2_part_masks);716717astc_helpers::log_astc_block trial_blk;718clear_obj(trial_blk);719trial_blk.m_grid_width = 4;720trial_blk.m_grid_height = 4;721722trial_blk.m_num_partitions = 2;723trial_blk.m_color_endpoint_modes[0] = 11;724trial_blk.m_color_endpoint_modes[1] = 11;725726uint32_t first_part_index = 0, last_part_index = basist::TOTAL_ASTC_BC6H_COMMON_PARTITIONS2;727728if (num_estimated_partitions)729{730first_part_index = 0;731last_part_index = num_estimated_partitions;732}733734for (uint32_t part_index_iter = first_part_index; part_index_iter < last_part_index; ++part_index_iter)735{736uint32_t part_index;737if (num_estimated_partitions)738{739part_index = pEstimated_partitions[part_index_iter];740assert(part_index < basist::TOTAL_ASTC_BC6H_COMMON_PARTITIONS2);741}742else743{744part_index = part_index_iter;745if (((1U << part_index) & coptions.m_mode11_part2_part_masks) == 0)746continue;747}748749const uint32_t astc_pattern = basist::g_astc_bc7_common_partitions2[part_index].m_astc;750const uint32_t bc7_pattern = basist::g_astc_bc7_common_partitions2[part_index].m_bc7;751const bool invert_flag = basist::g_astc_bc7_common_partitions2[part_index].m_invert;752753half_float part_pixels_half[2][16][3];754vec4F part_pixels_q16[2][16];755756uint32_t pixel_part_index[4][4]; // [y][x]757uint32_t num_part_pixels[2] = { 0, 0 };758759// Extract each subset's texels for this partition pattern760for (uint32_t y = 0; y < 4; y++)761{762for (uint32_t x = 0; x < 4; x++)763{764uint32_t part = basist::g_bc7_partition2[16 * bc7_pattern + x + y * 4];765if (invert_flag)766part = 1 - part;767768pixel_part_index[y][x] = part;769770const uint32_t n = num_part_pixels[part];771772part_pixels_half[part][n][0] = pBlock_pixels_half[x + y * 4][0];773part_pixels_half[part][n][1] = pBlock_pixels_half[x + y * 4][1];774part_pixels_half[part][n][2] = pBlock_pixels_half[x + y * 4][2];775part_pixels_q16[part][n] = pBlock_pixels_q16[x + y * 4];776777num_part_pixels[part] = n + 1;778}779}780781trial_blk.m_partition_id = (uint16_t)astc_pattern;782783for (uint32_t weight_ise_range = coptions.m_first_mode11_part2_weight_ise_range; weight_ise_range <= coptions.m_last_mode11_part2_weight_ise_range; weight_ise_range++)784{785bool direct_only = false;786uint32_t ise_endpoint_range = astc_helpers::BISE_64_LEVELS;787if (weight_ise_range == astc_helpers::BISE_4_LEVELS)788ise_endpoint_range = astc_helpers::BISE_40_LEVELS;789790uint8_t trial_endpoints[2][NUM_MODE11_ENDPOINTS], trial_weights[2][16];791uint32_t trial_submode11[2];792793clear_obj(trial_endpoints);794clear_obj(trial_weights);795clear_obj(trial_submode11);796797double total_trial_err = 0;798for (uint32_t pack_part_index = 0; pack_part_index < 2; pack_part_index++)799{800total_trial_err += encode_astc_hdr_block_mode_11(801num_part_pixels[pack_part_index], part_pixels_half[pack_part_index], part_pixels_q16[pack_part_index],802weight_ise_range, trial_submode11[pack_part_index], BIG_FLOAT_VAL,803&trial_endpoints[pack_part_index][0], &trial_weights[pack_part_index][0], coptions,804direct_only, ise_endpoint_range, coptions.m_mode11_uber_mode && (weight_ise_range >= astc_helpers::BISE_4_LEVELS) && coptions.m_allow_uber_mode, false,805coptions.m_first_mode11_submode, coptions.m_last_mode11_submode, false, cOrdinaryLeastSquares);806807} // pack_part_index808809if (total_trial_err < BIG_FLOAT_VAL)810{811trial_blk.m_weight_ise_range = (uint8_t)weight_ise_range;812trial_blk.m_endpoint_ise_range = (uint8_t)ise_endpoint_range;813814for (uint32_t pack_part_index = 0; pack_part_index < 2; pack_part_index++)815memcpy(&trial_blk.m_endpoints[pack_part_index * NUM_MODE11_ENDPOINTS], &trial_endpoints[pack_part_index][0], NUM_MODE11_ENDPOINTS);816817uint32_t src_pixel_index[2] = { 0, 0 };818for (uint32_t y = 0; y < 4; y++)819{820for (uint32_t x = 0; x < 4; x++)821{822uint32_t p = pixel_part_index[y][x];823trial_blk.m_weights[x + y * 4] = trial_weights[p][src_pixel_index[p]++];824}825}826827astc_hdr_4x4_pack_results results;828results.clear();829830results.m_best_block_error = total_trial_err;831results.m_best_submodes[0] = trial_submode11[0];832results.m_best_submodes[1] = trial_submode11[1];833results.m_best_pat_index = part_index;834835results.m_best_blk = trial_blk;836837bool status = transcode_bc6h_2subsets(part_index, results.m_best_blk, results.m_bc6h_block);838assert(status);839BASISU_NOTE_UNUSED(status);840841all_results.push_back(results);842}843844} // weight_ise_range845846} // part_index847}848849bool astc_hdr_4x4_enc_block(850const float* pRGBPixels, const basist::half_float *pRGBPixelsHalf,851const uastc_hdr_4x4_codec_options& coptions,852basisu::vector<astc_hdr_4x4_pack_results>& all_results)853{854assert(g_astc_hdr_enc_initialized);855if (!g_astc_hdr_enc_initialized)856{857// astc_hdr_enc_init() MUST be called first.858assert(0);859return false;860}861862assert(coptions.m_use_solid || coptions.m_use_mode11_part1 || coptions.m_use_mode7_part2 || coptions.m_use_mode7_part1 || coptions.m_use_mode11_part2);863864all_results.resize(0);865866const half_float (*pBlock_pixels_half)[16][3] = reinterpret_cast<const half_float(*)[16][3]>(pRGBPixelsHalf);867868vec4F block_linear_colors[16];869vec4F block_pixels_q16[16];870871bool is_greyscale = true;872873for (uint32_t i = 0; i < 16; i++)874{875const float fr = pRGBPixels[i * 3 + 0], fg = pRGBPixels[i * 3 + 1], fb = pRGBPixels[i * 3 + 2];876877// Sanity check the input block.878assert((fr >= 0) && (fr <= MAX_HALF_FLOAT) && (!std::isinf(fr)) && (!std::isnan(fr)));879assert((fg >= 0) && (fg <= MAX_HALF_FLOAT) && (!std::isinf(fg)) && (!std::isnan(fg)));880assert((fb >= 0) && (fb <= MAX_HALF_FLOAT) && (!std::isinf(fb)) && (!std::isnan(fb)));881882block_linear_colors[i].set(fr, fg, fb, 1.0f);883884const half_float hr = (*pBlock_pixels_half)[i][0];885assert(hr == basist::float_to_half(fr));886block_pixels_q16[i][0] = (float)half_to_qlog16(hr);887888const half_float hg = (*pBlock_pixels_half)[i][1];889assert(hg == basist::float_to_half(fg));890block_pixels_q16[i][1] = (float)half_to_qlog16(hg);891892const half_float hb = (*pBlock_pixels_half)[i][2];893assert(hb == basist::float_to_half(fb));894block_pixels_q16[i][2] = (float)half_to_qlog16(hb);895896block_pixels_q16[i][3] = 0.0f;897898if ((hr != hg) || (hr != hb))899is_greyscale = false;900} // i901902bool is_solid = false;903if (coptions.m_use_solid)904is_solid = pack_solid(block_linear_colors, all_results, coptions);905906if (!is_solid)907{908if ((is_greyscale) && (coptions.m_level == 0))909{910// Special case if it's a pure grayscale block - just try mode 7.911pack_mode7_single_part(*pBlock_pixels_half, block_pixels_q16, all_results, coptions, 1, 1);912pack_mode7_single_part(*pBlock_pixels_half, block_pixels_q16, all_results, coptions, UHDR_MODE7_PART1_LAST_ISE_RANGE, UHDR_MODE7_PART1_LAST_ISE_RANGE);913}914else915{916if (coptions.m_use_mode11_part1)917{918const size_t cur_num_results = all_results.size();919920pack_mode11(block_linear_colors, *pBlock_pixels_half, block_pixels_q16, all_results, coptions, coptions.m_first_mode11_weight_ise_range, coptions.m_last_mode11_weight_ise_range, false);921922if (coptions.m_last_mode11_weight_ise_range >= astc_helpers::BISE_12_LEVELS)923{924// Try constrained weights if we're allowed to use 12/16 level ISE weight modes925pack_mode11(block_linear_colors, *pBlock_pixels_half, block_pixels_q16, all_results, coptions, maximum<uint32_t>(coptions.m_first_mode11_weight_ise_range, astc_helpers::BISE_12_LEVELS), coptions.m_last_mode11_weight_ise_range, true);926}927928// If we couldn't get any mode 11 results at all, and we were restricted to just trying weight ISE range 8 (which required endpoint quantization) then929// fall back to weight ISE range 7 (which doesn't need any endpoint quantization).930// This is to guarantee we always get at least 1 non-solid result.931if (all_results.size() == cur_num_results)932{933if (coptions.m_first_mode11_weight_ise_range == astc_helpers::BISE_16_LEVELS)934{935pack_mode11(block_linear_colors, *pBlock_pixels_half, block_pixels_q16, all_results, coptions, astc_helpers::BISE_12_LEVELS, astc_helpers::BISE_12_LEVELS, false);936}937}938}939940if (coptions.m_use_mode7_part1)941{942// Mode 7 1-subset never requires endpoint quantization, so it cannot fail to find at least one usable solution.943pack_mode7_single_part(*pBlock_pixels_half, block_pixels_q16, all_results, coptions, coptions.m_first_mode7_part1_weight_ise_range, coptions.m_last_mode7_part1_weight_ise_range);944}945else if (is_greyscale)946{947// Special case if it's a pure grayscale block and mode 7 was disabled - try it anyway, because mode 11 has worse B channel quantization.948pack_mode7_single_part(*pBlock_pixels_half, block_pixels_q16, all_results, coptions, 1, 1);949pack_mode7_single_part(*pBlock_pixels_half, block_pixels_q16, all_results, coptions, UHDR_MODE7_PART1_LAST_ISE_RANGE, UHDR_MODE7_PART1_LAST_ISE_RANGE);950}951}952953bool have_est = false;954int best_parts[basist::TOTAL_ASTC_BC6H_COMMON_PARTITIONS2];955956if ((coptions.m_use_mode7_part2) || (coptions.m_use_mode11_part2))957{958if (coptions.m_use_estimated_partitions)959have_est = estimate_partition(*pBlock_pixels_half, best_parts, coptions.m_max_estimated_partitions);960}961962if (coptions.m_use_mode7_part2)963{964const size_t cur_num_results = all_results.size();965966pack_mode7_2part(*pBlock_pixels_half, block_pixels_q16,967all_results, coptions, have_est ? coptions.m_max_estimated_partitions : 0, best_parts,968coptions.m_first_mode7_part2_weight_ise_range, coptions.m_last_mode7_part2_weight_ise_range);969970// If we couldn't find any packable 2-subset mode 7 results at weight levels >= 5 levels (which always requires endpoint quant), then try falling back to971// 5 levels which doesn't require endpoint quantization.972if (all_results.size() == cur_num_results)973{974if (coptions.m_first_mode7_part2_weight_ise_range >= astc_helpers::BISE_5_LEVELS)975{976pack_mode7_2part(*pBlock_pixels_half, block_pixels_q16,977all_results, coptions, have_est ? coptions.m_max_estimated_partitions : 0, best_parts,978astc_helpers::BISE_4_LEVELS, astc_helpers::BISE_4_LEVELS);979}980}981}982983if (coptions.m_use_mode11_part2)984{985// This always requires endpoint quant, so it could fail to find any usable solutions.986pack_mode11_2part(*pBlock_pixels_half, block_pixels_q16, all_results, coptions, have_est ? coptions.m_max_estimated_partitions : 0, best_parts);987}988989if (coptions.m_refine_weights)990{991// TODO: This is quite slow.992for (uint32_t i = 0; i < all_results.size(); i++)993{994bool status = astc_hdr_4x4_refine_weights(pRGBPixelsHalf, all_results[i], coptions, coptions.m_bc6h_err_weight, &all_results[i].m_improved_via_refinement_flag);995assert(status);996BASISU_NOTE_UNUSED(status);997}998}9991000} // !is_solid10011002return true;1003}10041005bool astc_hdr_4x4_pack_results_to_block(astc_blk& dst_blk, const astc_hdr_4x4_pack_results& results)1006{1007assert(g_astc_hdr_enc_initialized);1008if (!g_astc_hdr_enc_initialized)1009return false;10101011if (results.m_is_solid)1012{1013memcpy(&dst_blk, &results.m_solid_blk, sizeof(results.m_solid_blk));1014}1015else1016{1017bool status = astc_helpers::pack_astc_block((astc_helpers::astc_block&)dst_blk, results.m_best_blk);1018if (!status)1019{1020assert(0);1021return false;1022}1023}10241025return true;1026}10271028// Refines a block's chosen weight indices, balancing BC6H and ASTC HDR error.1029bool astc_hdr_4x4_refine_weights(const half_float *pSource_block,1030astc_hdr_4x4_pack_results& cur_results, const uastc_hdr_4x4_codec_options& coptions, float bc6h_weight, bool *pImproved_flag)1031{1032if (pImproved_flag)1033*pImproved_flag = false;10341035if (cur_results.m_is_solid)1036return true;10371038const uint32_t total_weights = astc_helpers::get_ise_levels(cur_results.m_best_blk.m_weight_ise_range);1039assert((total_weights >= MIN_SUPPORTED_WEIGHT_LEVELS) && (total_weights <= MAX_SUPPORTED_WEIGHT_LEVELS));10401041double best_err[4][4];1042uint8_t best_weight[4][4];1043for (uint32_t y = 0; y < 4; y++)1044{1045for (uint32_t x = 0; x < 4; x++)1046{1047best_err[y][x] = BIG_FLOAT_VAL;1048best_weight[y][x] = 0;1049}1050}10511052astc_hdr_4x4_pack_results temp_results;10531054const float c_weights[3] = { coptions.m_r_err_scale, coptions.m_g_err_scale, 1.0f };10551056for (uint32_t weight_index = 0; weight_index < total_weights; weight_index++)1057{1058temp_results = cur_results;1059for (uint32_t i = 0; i < 16; i++)1060temp_results.m_best_blk.m_weights[i] = (uint8_t)weight_index;10611062half_float unpacked_astc_blk_rgba[4][4][4];1063bool res = astc_helpers::decode_block(temp_results.m_best_blk, unpacked_astc_blk_rgba, 4, 4, astc_helpers::cDecodeModeHDR16);1064assert(res);10651066basist::bc6h_block trial_bc6h_blk;1067res = basist::astc_hdr_transcode_to_bc6h(temp_results.m_best_blk, trial_bc6h_blk);1068assert(res);10691070half_float unpacked_bc6h_blk[4][4][3];1071res = unpack_bc6h(&trial_bc6h_blk, unpacked_bc6h_blk, false);1072assert(res);1073BASISU_NOTE_UNUSED(res);10741075for (uint32_t y = 0; y < 4; y++)1076{1077for (uint32_t x = 0; x < 4; x++)1078{1079double total_err = 0.0f;10801081for (uint32_t c = 0; c < 3; c++)1082{1083const half_float orig_c = pSource_block[(x + y * 4) * 3 + c];1084const double orig_c_q = q(orig_c, Q_LOG_BIAS_4x4);10851086const half_float astc_c = unpacked_astc_blk_rgba[y][x][c];1087const double astc_c_q = q(astc_c, Q_LOG_BIAS_4x4);1088const double astc_e = square(astc_c_q - orig_c_q) * c_weights[c];10891090const half_float bc6h_c = unpacked_bc6h_blk[y][x][c];1091const double bc6h_c_q = q(bc6h_c, Q_LOG_BIAS_4x4);1092const double bc6h_e = square(bc6h_c_q - orig_c_q) * c_weights[c];10931094const double overall_err = astc_e * (1.0f - bc6h_weight) + bc6h_e * bc6h_weight;10951096total_err += overall_err;10971098} // c10991100if (total_err < best_err[y][x])1101{1102best_err[y][x] = total_err;1103best_weight[y][x] = (uint8_t)weight_index;1104}11051106} // x1107} // y11081109} // weight_index11101111bool any_changed = false;1112for (uint32_t i = 0; i < 16; i++)1113{1114if (cur_results.m_best_blk.m_weights[i] != best_weight[i >> 2][i & 3])1115{1116any_changed = true;1117break;1118}1119}11201121if (any_changed)1122{1123memcpy(cur_results.m_best_blk.m_weights, best_weight, 16);11241125{1126bool res = basist::astc_hdr_transcode_to_bc6h(cur_results.m_best_blk, cur_results.m_bc6h_block);1127assert(res);1128BASISU_NOTE_UNUSED(res);11291130half_float unpacked_astc_blk_rgba[4][4][4];1131res = astc_helpers::decode_block(cur_results.m_best_blk, unpacked_astc_blk_rgba, 4, 4, astc_helpers::cDecodeModeHDR16);1132assert(res);11331134half_float unpacked_astc_blk_rgb[4][4][3];1135for (uint32_t y = 0; y < 4; y++)1136for (uint32_t x = 0; x < 4; x++)1137for (uint32_t c = 0; c < 3; c++)1138unpacked_astc_blk_rgb[y][x][c] = unpacked_astc_blk_rgba[y][x][c];11391140cur_results.m_best_block_error = compute_block_error(16, pSource_block, &unpacked_astc_blk_rgb[0][0][0], coptions);1141}11421143if (pImproved_flag)1144*pImproved_flag = true;1145}11461147return true;1148}11491150void astc_hdr_4x4_block_stats::update(const astc_hdr_4x4_pack_results& log_blk)1151{1152std::lock_guard<std::mutex> lck(m_mutex);11531154m_total_blocks++;11551156if (log_blk.m_improved_via_refinement_flag)1157m_total_refined++;11581159if (log_blk.m_is_solid)1160{1161m_total_solid++;1162}1163else1164{1165int best_weight_range = log_blk.m_best_blk.m_weight_ise_range;11661167if (log_blk.m_best_blk.m_color_endpoint_modes[0] == 7)1168{1169m_mode7_submode_hist[bounds_check(log_blk.m_best_submodes[0], 0U, 6U)]++;11701171if (log_blk.m_best_blk.m_num_partitions == 2)1172{1173m_total_mode7_2part++;11741175m_mode7_submode_hist[bounds_check(log_blk.m_best_submodes[1], 0U, 6U)]++;1176m_total_2part++;11771178m_weight_range_hist_7_2part[bounds_check(best_weight_range, 0, 11)]++;11791180m_part_hist[bounds_check(log_blk.m_best_pat_index, 0U, 32U)]++;1181}1182else1183{1184m_total_mode7_1part++;11851186m_weight_range_hist_7[bounds_check(best_weight_range, 0, 11)]++;1187}1188}1189else1190{1191m_mode11_submode_hist[bounds_check(log_blk.m_best_submodes[0], 0U, 9U)]++;1192if (log_blk.m_constrained_weights)1193m_total_mode11_1part_constrained_weights++;11941195if (log_blk.m_best_blk.m_num_partitions == 2)1196{1197m_total_mode11_2part++;11981199m_mode11_submode_hist[bounds_check(log_blk.m_best_submodes[1], 0U, 9U)]++;1200m_total_2part++;12011202m_weight_range_hist_11_2part[bounds_check(best_weight_range, 0, 11)]++;12031204m_part_hist[bounds_check(log_blk.m_best_pat_index, 0U, 32U)]++;1205}1206else1207{1208m_total_mode11_1part++;12091210m_weight_range_hist_11[bounds_check(best_weight_range, 0, 11)]++;1211}1212}1213}1214}12151216void astc_hdr_4x4_block_stats::print()1217{1218std::lock_guard<std::mutex> lck(m_mutex);12191220assert(m_total_blocks);1221if (!m_total_blocks)1222return;12231224printf("\nLow-level ASTC Encoder Statistics:\n");1225printf("Total blocks: %u\n", m_total_blocks);1226printf("Total solid: %u %3.2f%%\n", m_total_solid, (m_total_solid * 100.0f) / m_total_blocks);1227printf("Total refined: %u %3.2f%%\n", m_total_refined, (m_total_refined * 100.0f) / m_total_blocks);12281229printf("Total mode 11, 1 partition: %u %3.2f%%\n", m_total_mode11_1part, (m_total_mode11_1part * 100.0f) / m_total_blocks);1230printf("Total mode 11, 1 partition, constrained weights: %u %3.2f%%\n", m_total_mode11_1part_constrained_weights, (m_total_mode11_1part_constrained_weights * 100.0f) / m_total_blocks);1231printf("Total mode 11, 2 partition: %u %3.2f%%\n", m_total_mode11_2part, (m_total_mode11_2part * 100.0f) / m_total_blocks);12321233printf("Total mode 7, 1 partition: %u %3.2f%%\n", m_total_mode7_1part, (m_total_mode7_1part * 100.0f) / m_total_blocks);1234printf("Total mode 7, 2 partition: %u %3.2f%%\n", m_total_mode7_2part, (m_total_mode7_2part * 100.0f) / m_total_blocks);12351236printf("Total 2 partitions: %u %3.2f%%\n", m_total_2part, (m_total_2part * 100.0f) / m_total_blocks);1237printf("\n");12381239printf("ISE texel weight range histogram mode 11:\n");1240for (uint32_t i = 1; i <= UHDR_MODE11_LAST_ISE_RANGE; i++)1241printf("%u %u\n", i, m_weight_range_hist_11[i]);1242printf("\n");12431244printf("ISE texel weight range histogram mode 11, 2 partition:\n");1245for (uint32_t i = 1; i <= UHDR_MODE11_PART2_LAST_ISE_RANGE; i++)1246printf("%u %u\n", i, m_weight_range_hist_11_2part[i]);1247printf("\n");12481249printf("ISE texel weight range histogram mode 7:\n");1250for (uint32_t i = 1; i <= UHDR_MODE7_PART1_LAST_ISE_RANGE; i++)1251printf("%u %u\n", i, m_weight_range_hist_7[i]);1252printf("\n");12531254printf("ISE texel weight range histogram mode 7, 2 partition:\n");1255for (uint32_t i = 1; i <= UHDR_MODE7_PART2_LAST_ISE_RANGE; i++)1256printf("%u %u\n", i, m_weight_range_hist_7_2part[i]);1257printf("\n");12581259printf("Mode 11 submode histogram:\n");1260for (uint32_t i = 0; i <= MODE11_TOTAL_SUBMODES; i++) // +1 because of the extra direct encoding1261printf("%u %u\n", i, m_mode11_submode_hist[i]);1262printf("\n");12631264printf("Mode 7 submode histogram:\n");1265for (uint32_t i = 0; i < MODE7_TOTAL_SUBMODES; i++)1266printf("%u %u\n", i, m_mode7_submode_hist[i]);1267printf("\n");12681269printf("Partition pattern table usage histogram:\n");1270for (uint32_t i = 0; i < basist::TOTAL_ASTC_BC7_COMMON_PARTITIONS2; i++)1271printf("%u:%u ", i, m_part_hist[i]);1272printf("\n\n");1273}12741275} // namespace basisu1276127712781279