1// SPDX-License-Identifier: Apache-2.0 2// ---------------------------------------------------------------------------- 3// Copyright 2011-2024 Arm Limited 4// 5// Licensed under the Apache License, Version 2.0 (the "License"); you may not 6// use this file except in compliance with the License. You may obtain a copy 7// of the License at: 8// 9// http://www.apache.org/licenses/LICENSE-2.0 10// 11// Unless required by applicable law or agreed to in writing, software 12// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14// License for the specific language governing permissions and limitations 15// under the License. 16// ---------------------------------------------------------------------------- 17 18#if !defined(ASTCENC_DECOMPRESS_ONLY) 19 20/** 21 * @brief Functions for angular-sum algorithm for weight alignment. 22 * 23 * This algorithm works as follows: 24 * - we compute a complex number P as (cos s*i, sin s*i) for each weight, 25 * where i is the input value and s is a scaling factor based on the spacing between the weights. 26 * - we then add together complex numbers for all the weights. 27 * - we then compute the length and angle of the resulting sum. 28 * 29 * This should produce the following results: 30 * - perfect alignment results in a vector whose length is equal to the sum of lengths of all inputs 31 * - even distribution results in a vector of length 0. 32 * - all samples identical results in perfect alignment for every scaling. 33 * 34 * For each scaling factor within a given set, we compute an alignment factor from 0 to 1. This 35 * should then result in some scalings standing out as having particularly good alignment factors; 36 * we can use this to produce a set of candidate scale/shift values for various quantization levels; 37 * we should then actually try them and see what happens. 38 */ 39 40#include "astcenc_internal.h" 41#include "astcenc_vecmathlib.h" 42 43#include <stdio.h> 44#include <cassert> 45#include <cstring> 46 47static constexpr unsigned int ANGULAR_STEPS { 32 }; 48 49static_assert((ANGULAR_STEPS % ASTCENC_SIMD_WIDTH) == 0, 50 "ANGULAR_STEPS must be multiple of ASTCENC_SIMD_WIDTH"); 51 52static_assert(ANGULAR_STEPS >= 32, 53 "ANGULAR_STEPS must be at least max(steps_for_quant_level)"); 54 55// Store a reduced sin/cos table for 64 possible weight values; this causes 56// slight quality loss compared to using sin() and cos() directly. Must be 2^N. 57static constexpr unsigned int SINCOS_STEPS { 64 }; 58 59static const uint8_t steps_for_quant_level[12] { 60 2, 3, 4, 5, 6, 8, 10, 12, 16, 20, 24, 32 61}; 62 63ASTCENC_ALIGNAS static float sin_table[SINCOS_STEPS][ANGULAR_STEPS]; 64ASTCENC_ALIGNAS static float cos_table[SINCOS_STEPS][ANGULAR_STEPS]; 65 66#if defined(ASTCENC_DIAGNOSTICS) 67 static bool print_once { true }; 68#endif 69 70/* See header for documentation. */ 71void prepare_angular_tables() 72{ 73 for (unsigned int i = 0; i < ANGULAR_STEPS; i++) 74 { 75 float angle_step = static_cast<float>(i + 1); 76 77 for (unsigned int j = 0; j < SINCOS_STEPS; j++) 78 { 79 sin_table[j][i] = static_cast<float>(sinf((2.0f * astc::PI / (SINCOS_STEPS - 1.0f)) * angle_step * static_cast<float>(j))); 80 cos_table[j][i] = static_cast<float>(cosf((2.0f * astc::PI / (SINCOS_STEPS - 1.0f)) * angle_step * static_cast<float>(j))); 81 } 82 } 83} 84 85/** 86 * @brief Compute the angular alignment factors and offsets. 87 * 88 * @param weight_count The number of (decimated) weights. 89 * @param dec_weight_ideal_value The ideal decimated unquantized weight values. 90 * @param max_angular_steps The maximum number of steps to be tested. 91 * @param[out] offsets The output angular offsets array. 92 */ 93static void compute_angular_offsets( 94 unsigned int weight_count, 95 const float* dec_weight_ideal_value, 96 unsigned int max_angular_steps, 97 float* offsets 98) { 99 promise(weight_count > 0); 100 promise(max_angular_steps > 0); 101 102 ASTCENC_ALIGNAS int isamplev[BLOCK_MAX_WEIGHTS]; 103 104 // Precompute isample; arrays are always allocated 64 elements long 105 for (unsigned int i = 0; i < weight_count; i += ASTCENC_SIMD_WIDTH) 106 { 107 // Add 2^23 and interpreting bits extracts round-to-nearest int 108 vfloat sample = loada(dec_weight_ideal_value + i) * (SINCOS_STEPS - 1.0f) + vfloat(12582912.0f); 109 vint isample = float_as_int(sample) & vint((SINCOS_STEPS - 1)); 110 storea(isample, isamplev + i); 111 } 112 113 // Arrays are multiple of SIMD width (ANGULAR_STEPS), safe to overshoot max 114 vfloat mult = vfloat(1.0f / (2.0f * astc::PI)); 115 116 for (unsigned int i = 0; i < max_angular_steps; i += ASTCENC_SIMD_WIDTH) 117 { 118 vfloat anglesum_x = vfloat::zero(); 119 vfloat anglesum_y = vfloat::zero(); 120 121 for (unsigned int j = 0; j < weight_count; j++) 122 { 123 int isample = isamplev[j]; 124 anglesum_x += loada(cos_table[isample] + i); 125 anglesum_y += loada(sin_table[isample] + i); 126 } 127 128 vfloat angle = atan2(anglesum_y, anglesum_x); 129 vfloat ofs = angle * mult; 130 storea(ofs, offsets + i); 131 } 132} 133 134/** 135 * @brief For a given step size compute the lowest and highest weight. 136 * 137 * Compute the lowest and highest weight that results from quantizing using the given stepsize and 138 * offset, and then compute the resulting error. The cut errors indicate the error that results from 139 * forcing samples that should have had one weight value one step up or down. 140 * 141 * @param weight_count The number of (decimated) weights. 142 * @param dec_weight_ideal_value The ideal decimated unquantized weight values. 143 * @param max_angular_steps The maximum number of steps to be tested. 144 * @param max_quant_steps The maximum quantization level to be tested. 145 * @param offsets The angular offsets array. 146 * @param[out] lowest_weight Per angular step, the lowest weight. 147 * @param[out] weight_span Per angular step, the span between lowest and highest weight. 148 * @param[out] error Per angular step, the error. 149 * @param[out] cut_low_weight_error Per angular step, the low weight cut error. 150 * @param[out] cut_high_weight_error Per angular step, the high weight cut error. 151 */ 152#if ASTCENC_NEON != 0 153static void compute_lowest_and_highest_weight( 154 QualityProfile privateProfile, 155 unsigned int weight_count, 156 const float* dec_weight_ideal_value, 157 unsigned int max_angular_steps, 158 unsigned int max_quant_steps, 159 const float* offsets, 160 float* lowest_weight, 161 int* weight_span, 162 float* error, 163 float* cut_low_weight_error, 164 float* cut_high_weight_error 165) { 166 promise(weight_count > 0); 167 promise(max_angular_steps > 0); 168 169 vfloat rcp_stepsize = vfloat::lane_id() + vfloat(1.0f); 170 171 float max_weight = 1.0f; 172 float min_weight = 0.0f; 173 // in HIGH_SPEED_PROFILE, max_weight is always equal to 1.0, and min_weight is always equal to 0 174 if (privateProfile != HIGH_SPEED_PROFILE) 175 { 176 max_weight = dec_weight_ideal_value[0]; 177 min_weight = dec_weight_ideal_value[0]; 178 for (unsigned int j = 1; j < weight_count; j++) 179 { 180 float weight = dec_weight_ideal_value[j]; 181 __asm__ volatile("fmax %s0, %s0, %s1" : "+w"(max_weight) : "w"(weight)); 182 __asm__ volatile("fmin %s0, %s0, %s1" : "+w"(min_weight) : "w"(weight)); 183 } 184 } 185 186 // Arrays are ANGULAR_STEPS long, so always safe to run full vectors 187 for (unsigned int sp = 0; sp < max_angular_steps; sp += ASTCENC_SIMD_WIDTH) 188 { 189 vfloat errval = vfloat::zero(); 190 vfloat cut_low_weight_err = vfloat::zero(); 191 vfloat cut_high_weight_err = vfloat::zero(); 192 vfloat offset = loada(offsets + sp); 193 194 offset = (vfloat)vnegq_f32(offset.m); 195 vfloat maxidx = vfloat::zero(); 196 vfloat minidx = vfloat::zero(); 197 198 if (privateProfile == HIGH_SPEED_PROFILE) 199 { 200 maxidx = round((vfloat)vaddq_f32(rcp_stepsize.m, offset.m)); 201 minidx = round(offset); 202 } 203 else 204 { 205 maxidx = round((vfloat)vfmaq_n_f32(offset.m, rcp_stepsize.m, max_weight)); 206 minidx = round((vfloat)vfmaq_n_f32(offset.m, rcp_stepsize.m, min_weight)); 207 } 208 209 for (unsigned int j = 0; j < weight_count; j++) 210 { 211 vfloat sval = (vfloat)vfmaq_n_f32(offset.m, rcp_stepsize.m, *(dec_weight_ideal_value + j)); 212 vfloat svalrte = round(sval); 213 vfloat diff = sval - svalrte; 214 errval += diff * diff; 215 216 // Accumulate on min hit 217 vmask mask = svalrte == minidx; 218 vfloat accum = cut_low_weight_err + vfloat(1.0f) - vfloat(2.0f) * diff; 219 cut_low_weight_err = select(cut_low_weight_err, accum, mask); 220 221 // Accumulate on max hit 222 mask = svalrte == maxidx; 223 accum = cut_high_weight_err + vfloat(1.0f) + vfloat(2.0f) * diff; 224 cut_high_weight_err = select(cut_high_weight_err, accum, mask); 225 } 226 227 // Write out min weight and weight span; clamp span to a usable range 228 vint span = float_to_int(maxidx - minidx + vfloat(1)); 229 span = min(span, vint(max_quant_steps + 3)); 230 span = max(span, vint(2)); 231 storea(minidx, lowest_weight + sp); 232 storea(span, weight_span + sp); 233 234 // The cut_(lowest/highest)_weight_error indicate the error that results from forcing 235 // samples that should have had the weight value one step (up/down). 236 vfloat ssize = 1.0f / rcp_stepsize; 237 vfloat errscale = ssize * ssize; 238 storea(errval * errscale, error + sp); 239 storea(cut_low_weight_err * errscale, cut_low_weight_error + sp); 240 storea(cut_high_weight_err * errscale, cut_high_weight_error + sp); 241 242 rcp_stepsize = rcp_stepsize + vfloat(ASTCENC_SIMD_WIDTH); 243 } 244} 245#else 246static void compute_lowest_and_highest_weight( 247 QualityProfile privateProfile, 248 unsigned int weight_count, 249 const float* dec_weight_ideal_value, 250 unsigned int max_angular_steps, 251 unsigned int max_quant_steps, 252 const float* offsets, 253 float* lowest_weight, 254 int* weight_span, 255 float* error, 256 float* cut_low_weight_error, 257 float* cut_high_weight_error 258) { 259 (void) privateProfile; 260 promise(weight_count > 0); 261 promise(max_angular_steps > 0); 262 263 vfloat rcp_stepsize = vfloat::lane_id() + vfloat(1.0f); 264 265 // Arrays are ANGULAR_STEPS long, so always safe to run full vectors 266 for (unsigned int sp = 0; sp < max_angular_steps; sp += ASTCENC_SIMD_WIDTH) 267 { 268 vfloat minidx(128.0f); 269 vfloat maxidx(-128.0f); 270 vfloat errval = vfloat::zero(); 271 vfloat cut_low_weight_err = vfloat::zero(); 272 vfloat cut_high_weight_err = vfloat::zero(); 273 vfloat offset = loada(offsets + sp); 274 275 for (unsigned int j = 0; j < weight_count; j++) 276 { 277 vfloat sval = load1(dec_weight_ideal_value + j) * rcp_stepsize - offset; 278 vfloat svalrte = round(sval); 279 vfloat diff = sval - svalrte; 280 errval += diff * diff; 281 282 // Reset tracker on min hit 283 vmask mask = svalrte < minidx; 284 minidx = select(minidx, svalrte, mask); 285 cut_low_weight_err = select(cut_low_weight_err, vfloat::zero(), mask); 286 287 // Accumulate on min hit 288 mask = svalrte == minidx; 289 vfloat accum = cut_low_weight_err + vfloat(1.0f) - vfloat(2.0f) * diff; 290 cut_low_weight_err = select(cut_low_weight_err, accum, mask); 291 292 // Reset tracker on max hit 293 mask = svalrte > maxidx; 294 maxidx = select(maxidx, svalrte, mask); 295 cut_high_weight_err = select(cut_high_weight_err, vfloat::zero(), mask); 296 297 // Accumulate on max hit 298 mask = svalrte == maxidx; 299 accum = cut_high_weight_err + vfloat(1.0f) + vfloat(2.0f) * diff; 300 cut_high_weight_err = select(cut_high_weight_err, accum, mask); 301 } 302 303 // Write out min weight and weight span; clamp span to a usable range 304 vint span = float_to_int(maxidx - minidx + vfloat(1)); 305 span = min(span, vint(max_quant_steps + 3)); 306 span = max(span, vint(2)); 307 storea(minidx, lowest_weight + sp); 308 storea(span, weight_span + sp); 309 310 // The cut_(lowest/highest)_weight_error indicate the error that results from forcing 311 // samples that should have had the weight value one step (up/down). 312 vfloat ssize = 1.0f / rcp_stepsize; 313 vfloat errscale = ssize * ssize; 314 storea(errval * errscale, error + sp); 315 storea(cut_low_weight_err * errscale, cut_low_weight_error + sp); 316 storea(cut_high_weight_err * errscale, cut_high_weight_error + sp); 317 318 rcp_stepsize = rcp_stepsize + vfloat(ASTCENC_SIMD_WIDTH); 319 } 320} 321#endif 322 323/** 324 * @brief The main function for the angular algorithm. 325 * 326 * @param weight_count The number of (decimated) weights. 327 * @param dec_weight_ideal_value The ideal decimated unquantized weight values. 328 * @param max_quant_level The maximum quantization level to be tested. 329 * @param[out] low_value Per angular step, the lowest weight value. 330 * @param[out] high_value Per angular step, the highest weight value. 331 */ 332static void compute_angular_endpoints_for_quant_levels( 333 QualityProfile privateProfile, 334 unsigned int weight_count, 335 const float* dec_weight_ideal_value, 336 unsigned int max_quant_level, 337 float low_value[TUNE_MAX_ANGULAR_QUANT + 1], 338 float high_value[TUNE_MAX_ANGULAR_QUANT + 1] 339) { 340 unsigned int max_quant_steps = steps_for_quant_level[max_quant_level]; 341 unsigned int max_angular_steps = steps_for_quant_level[max_quant_level]; 342 343 ASTCENC_ALIGNAS float angular_offsets[ANGULAR_STEPS]; 344 345 compute_angular_offsets(weight_count, dec_weight_ideal_value, 346 max_angular_steps, angular_offsets); 347 348 ASTCENC_ALIGNAS float lowest_weight[ANGULAR_STEPS]; 349 ASTCENC_ALIGNAS int32_t weight_span[ANGULAR_STEPS]; 350 ASTCENC_ALIGNAS float error[ANGULAR_STEPS]; 351 ASTCENC_ALIGNAS float cut_low_weight_error[ANGULAR_STEPS]; 352 ASTCENC_ALIGNAS float cut_high_weight_error[ANGULAR_STEPS]; 353 354 compute_lowest_and_highest_weight(privateProfile, weight_count, dec_weight_ideal_value, 355 max_angular_steps, max_quant_steps, 356 angular_offsets, lowest_weight, weight_span, error, 357 cut_low_weight_error, cut_high_weight_error); 358 359 // For each quantization level, find the best error terms. Use packed vectors so data-dependent 360 // branches can become selects. This involves some integer to float casts, but the values are 361 // small enough so they never round the wrong way. 362 vfloat4 best_results[36]; 363 364 // Initialize the array to some safe defaults 365 promise(max_quant_steps > 0); 366 for (unsigned int i = 0; i < (max_quant_steps + 4); i++) 367 { 368 // Lane<0> = Best error 369 // Lane<1> = Best scale; -1 indicates no solution found 370 // Lane<2> = Cut low weight 371 best_results[i] = vfloat4(ERROR_CALC_DEFAULT, -1.0f, 0.0f, 0.0f); 372 } 373 374 promise(max_angular_steps > 0); 375 for (unsigned int i = 0; i < max_angular_steps; i++) 376 { 377 float i_flt = static_cast<float>(i); 378 379 int idx_span = weight_span[i]; 380 381 float error_cut_low = error[i] + cut_low_weight_error[i]; 382 float error_cut_high = error[i] + cut_high_weight_error[i]; 383 float error_cut_low_high = error[i] + cut_low_weight_error[i] + cut_high_weight_error[i]; 384 385 // Check best error against record N 386 vfloat4 best_result = best_results[idx_span]; 387 vfloat4 new_result = vfloat4(error[i], i_flt, 0.0f, 0.0f); 388 vmask4 mask = vfloat4(best_result.lane<0>()) > vfloat4(error[i]); 389 best_results[idx_span] = select(best_result, new_result, mask); 390 391 // Check best error against record N-1 with either cut low or cut high 392 best_result = best_results[idx_span - 1]; 393 394 new_result = vfloat4(error_cut_low, i_flt, 1.0f, 0.0f); 395 mask = vfloat4(best_result.lane<0>()) > vfloat4(error_cut_low); 396 best_result = select(best_result, new_result, mask); 397 398 new_result = vfloat4(error_cut_high, i_flt, 0.0f, 0.0f); 399 mask = vfloat4(best_result.lane<0>()) > vfloat4(error_cut_high); 400 best_results[idx_span - 1] = select(best_result, new_result, mask); 401 402 // Check best error against record N-2 with both cut low and high 403 best_result = best_results[idx_span - 2]; 404 new_result = vfloat4(error_cut_low_high, i_flt, 1.0f, 0.0f); 405 mask = vfloat4(best_result.lane<0>()) > vfloat4(error_cut_low_high); 406 best_results[idx_span - 2] = select(best_result, new_result, mask); 407 } 408 409 for (unsigned int i = 0; i <= max_quant_level; i++) 410 { 411 unsigned int q = steps_for_quant_level[i]; 412 int bsi = static_cast<int>(best_results[q].lane<1>()); 413 414 // Did we find anything? 415#if defined(ASTCENC_DIAGNOSTICS) 416 if ((bsi < 0) && print_once) 417 { 418 print_once = false; 419 printf("INFO: Unable to find full encoding within search error limit.\n\n"); 420 } 421#endif 422 423 bsi = astc::max(0, bsi); 424 425 float lwi = lowest_weight[bsi] + best_results[q].lane<2>(); 426 float hwi = lwi + static_cast<float>(q) - 1.0f; 427 428 float stepsize = 1.0f / (1.0f + static_cast<float>(bsi)); 429 low_value[i] = (angular_offsets[bsi] + lwi) * stepsize; 430 high_value[i] = (angular_offsets[bsi] + hwi) * stepsize; 431 } 432} 433 434/* See header for documentation. */ 435void compute_angular_endpoints_1plane( 436 QualityProfile privateProfile, 437 bool only_always, 438 const block_size_descriptor& bsd, 439 const float* dec_weight_ideal_value, 440 unsigned int max_weight_quant, 441 compression_working_buffers& tmpbuf 442) { 443 float (&low_value)[WEIGHTS_MAX_BLOCK_MODES] = tmpbuf.weight_low_value1; 444 float (&high_value)[WEIGHTS_MAX_BLOCK_MODES] = tmpbuf.weight_high_value1; 445 446 float (&low_values)[WEIGHTS_MAX_DECIMATION_MODES][TUNE_MAX_ANGULAR_QUANT + 1] = tmpbuf.weight_low_values1; 447 float (&high_values)[WEIGHTS_MAX_DECIMATION_MODES][TUNE_MAX_ANGULAR_QUANT + 1] = tmpbuf.weight_high_values1; 448 449 unsigned int max_decimation_modes = only_always ? bsd.decimation_mode_count_always 450 : bsd.decimation_mode_count_selected; 451 promise(max_decimation_modes > 0); 452 for (unsigned int i = 0; i < max_decimation_modes; i++) 453 { 454 const decimation_mode& dm = bsd.decimation_modes[i]; 455 if (!dm.is_ref_1plane(static_cast<quant_method>(max_weight_quant))) 456 { 457 continue; 458 } 459 460 unsigned int weight_count = bsd.get_decimation_info(i).weight_count; 461 462 unsigned int max_precision = dm.maxprec_1plane; 463 if (max_precision > TUNE_MAX_ANGULAR_QUANT) 464 { 465 max_precision = TUNE_MAX_ANGULAR_QUANT; 466 } 467 468 if (max_precision > max_weight_quant) 469 { 470 max_precision = max_weight_quant; 471 } 472 473 compute_angular_endpoints_for_quant_levels( 474 privateProfile, 475 weight_count, 476 dec_weight_ideal_value + i * BLOCK_MAX_WEIGHTS, 477 max_precision, low_values[i], high_values[i]); 478 } 479 480 unsigned int max_block_modes = only_always ? bsd.block_mode_count_1plane_always 481 : bsd.block_mode_count_1plane_selected; 482 promise(max_block_modes > 0); 483 for (unsigned int i = 0; i < max_block_modes; i++) 484 { 485 const block_mode& bm = bsd.block_modes[i]; 486 assert(!bm.is_dual_plane); 487 488 unsigned int quant_mode = bm.quant_mode; 489 unsigned int decim_mode = bm.decimation_mode; 490 491 if (quant_mode <= TUNE_MAX_ANGULAR_QUANT) 492 { 493 low_value[i] = low_values[decim_mode][quant_mode]; 494 high_value[i] = high_values[decim_mode][quant_mode]; 495 } 496 else 497 { 498 low_value[i] = 0.0f; 499 high_value[i] = 1.0f; 500 } 501 } 502} 503 504/* See header for documentation. */ 505void compute_angular_endpoints_2planes( 506 QualityProfile privateProfile, 507 const block_size_descriptor& bsd, 508 const float* dec_weight_ideal_value, 509 unsigned int max_weight_quant, 510 compression_working_buffers& tmpbuf 511) { 512 float (&low_value1)[WEIGHTS_MAX_BLOCK_MODES] = tmpbuf.weight_low_value1; 513 float (&high_value1)[WEIGHTS_MAX_BLOCK_MODES] = tmpbuf.weight_high_value1; 514 float (&low_value2)[WEIGHTS_MAX_BLOCK_MODES] = tmpbuf.weight_low_value2; 515 float (&high_value2)[WEIGHTS_MAX_BLOCK_MODES] = tmpbuf.weight_high_value2; 516 517 float (&low_values1)[WEIGHTS_MAX_DECIMATION_MODES][TUNE_MAX_ANGULAR_QUANT + 1] = tmpbuf.weight_low_values1; 518 float (&high_values1)[WEIGHTS_MAX_DECIMATION_MODES][TUNE_MAX_ANGULAR_QUANT + 1] = tmpbuf.weight_high_values1; 519 float (&low_values2)[WEIGHTS_MAX_DECIMATION_MODES][TUNE_MAX_ANGULAR_QUANT + 1] = tmpbuf.weight_low_values2; 520 float (&high_values2)[WEIGHTS_MAX_DECIMATION_MODES][TUNE_MAX_ANGULAR_QUANT + 1] = tmpbuf.weight_high_values2; 521 522 promise(bsd.decimation_mode_count_selected > 0); 523 for (unsigned int i = 0; i < bsd.decimation_mode_count_selected; i++) 524 { 525 const decimation_mode& dm = bsd.decimation_modes[i]; 526 if (!dm.is_ref_2plane(static_cast<quant_method>(max_weight_quant))) 527 { 528 continue; 529 } 530 531 unsigned int weight_count = bsd.get_decimation_info(i).weight_count; 532 533 unsigned int max_precision = dm.maxprec_2planes; 534 if (max_precision > TUNE_MAX_ANGULAR_QUANT) 535 { 536 max_precision = TUNE_MAX_ANGULAR_QUANT; 537 } 538 539 if (max_precision > max_weight_quant) 540 { 541 max_precision = max_weight_quant; 542 } 543 544 compute_angular_endpoints_for_quant_levels( 545 privateProfile, 546 weight_count, 547 dec_weight_ideal_value + i * BLOCK_MAX_WEIGHTS, 548 max_precision, low_values1[i], high_values1[i]); 549 550 compute_angular_endpoints_for_quant_levels( 551 privateProfile, 552 weight_count, 553 dec_weight_ideal_value + i * BLOCK_MAX_WEIGHTS + WEIGHTS_PLANE2_OFFSET, 554 max_precision, low_values2[i], high_values2[i]); 555 } 556 557 unsigned int start = bsd.block_mode_count_1plane_selected; 558 unsigned int end = bsd.block_mode_count_1plane_2plane_selected; 559 for (unsigned int i = start; i < end; i++) 560 { 561 const block_mode& bm = bsd.block_modes[i]; 562 unsigned int quant_mode = bm.quant_mode; 563 unsigned int decim_mode = bm.decimation_mode; 564 565 if (quant_mode <= TUNE_MAX_ANGULAR_QUANT) 566 { 567 low_value1[i] = low_values1[decim_mode][quant_mode]; 568 high_value1[i] = high_values1[decim_mode][quant_mode]; 569 low_value2[i] = low_values2[decim_mode][quant_mode]; 570 high_value2[i] = high_values2[decim_mode][quant_mode]; 571 } 572 else 573 { 574 low_value1[i] = 0.0f; 575 high_value1[i] = 1.0f; 576 low_value2[i] = 0.0f; 577 high_value2[i] = 1.0f; 578 } 579 } 580} 581 582#endif 583