static float compress_symbolic_block_for_partition_2planes(
	const astcenc_config& config,
	const block_size_descriptor& bsd,
	const image_block& blk,
	const error_weight_block& ewb,
	float tune_errorval_threshold,
	unsigned int plane2_component,
	symbolic_compressed_block& scb,
	compression_working_buffers& tmpbuf
) {
	promise(config.tune_candidate_limit > 0);
	promise(config.tune_refinement_limit > 0);
	promise(bsd.decimation_mode_count > 0);

	// Compute ideal weights and endpoint colors, with no quantization or decimation
	endpoints_and_weights& ei1 = tmpbuf.ei1;
	endpoints_and_weights& ei2 = tmpbuf.ei2;
	endpoints_and_weights* eix1 = tmpbuf.eix1;
	endpoints_and_weights* eix2 = tmpbuf.eix2;
	compute_ideal_colors_and_weights_2planes(bsd, blk, ewb, plane2_component, ei1, ei2);

	// Compute ideal weights and endpoint colors for every decimation
	float *dec_weights_ideal_value = tmpbuf.dec_weights_ideal_value;
	float *dec_weights_ideal_sig = tmpbuf.dec_weights_ideal_sig;
	float *dec_weights_quant_uvalue = tmpbuf.dec_weights_quant_uvalue;
	uint8_t *dec_weights_quant_pvalue = tmpbuf.dec_weights_quant_pvalue;

	// For each decimation mode, compute an ideal set of weights with no quantization
	for (unsigned int i = 0; i < bsd.decimation_mode_count; i++)
	{
		const auto& dm = bsd.get_decimation_mode(i);
		if (dm.maxprec_2planes < 0 || !dm.percentile_hit)
		{
			continue;
		}

		const auto& di = bsd.get_decimation_info(i);

		compute_ideal_weights_for_decimation(
		    ei1,
		    eix1[i],
		    di,
		    dec_weights_ideal_value + i * BLOCK_MAX_WEIGHTS,
		    dec_weights_ideal_sig + i * BLOCK_MAX_WEIGHTS);

		compute_ideal_weights_for_decimation(
		    ei2,
		    eix2[i],
		    di,
		    dec_weights_ideal_value + i * BLOCK_MAX_WEIGHTS + WEIGHTS_PLANE2_OFFSET,
		    dec_weights_ideal_sig +  i * BLOCK_MAX_WEIGHTS + WEIGHTS_PLANE2_OFFSET);
	}

	// Compute maximum colors for the endpoints and ideal weights, then for each endpoint and ideal
	// weight pair, compute the smallest weight that will result in a color value greater than 1
	vfloat4 min_ep1(10.0f);
	vfloat4 min_ep2(10.0f);

	vfloat4 ep1 = (vfloat4(1.0f) - ei1.ep.endpt0[0]) / (ei1.ep.endpt1[0] - ei1.ep.endpt0[0]);
	vmask4 use_ep1 = (ep1 > vfloat4(0.5f)) & (ep1 < min_ep1);
	min_ep1 = select(min_ep1, ep1, use_ep1);

	vfloat4 ep2 = (vfloat4(1.0f) - ei2.ep.endpt0[0]) / (ei2.ep.endpt1[0] - ei2.ep.endpt0[0]);
	vmask4 use_ep2 = (ep2 > vfloat4(0.5f)) & (ep2 < min_ep2);
	min_ep2 = select(min_ep2, ep2, use_ep2);

	vfloat4 err_max(ERROR_CALC_DEFAULT);
	vmask4 err_mask = vint4::lane_id() == vint4(plane2_component);

	// Set the plane2 component to max error in ep1
	min_ep1 = select(min_ep1, err_max, err_mask);

	float min_wt_cutoff1 = hmin_s(min_ep1);

	// Set the minwt2 to the plane2 component min in ep2
	float min_wt_cutoff2 = hmin_s(select(err_max, min_ep2, err_mask));

	float weight_low_value1[WEIGHTS_MAX_BLOCK_MODES];
	float weight_high_value1[WEIGHTS_MAX_BLOCK_MODES];
	float weight_low_value2[WEIGHTS_MAX_BLOCK_MODES];
	float weight_high_value2[WEIGHTS_MAX_BLOCK_MODES];

	compute_angular_endpoints_2planes(
	    config.tune_low_weight_count_limit,
	    bsd, dec_weights_ideal_value, dec_weights_ideal_sig,
	    weight_low_value1, weight_high_value1,
	    weight_low_value2, weight_high_value2);

	// For each mode (which specifies a decimation and a quantization):
	//     * Compute number of bits needed for the quantized weights
	//     * Generate an optimized set of quantized weights
	//     * Compute quantization errors for the mode

	int qwt_bitcounts[WEIGHTS_MAX_BLOCK_MODES];
	float qwt_errors[WEIGHTS_MAX_BLOCK_MODES];
	for (unsigned int i = 0; i < bsd.block_mode_count; ++i)
	{
		const block_mode& bm = bsd.block_modes[i];
		if (!bm.is_dual_plane || !bm.percentile_hit)
		{
			qwt_errors[i] = 1e38f;
			continue;
		}

		unsigned int decimation_mode = bm.decimation_mode;
		const auto& di = bsd.get_decimation_info(decimation_mode);

		if (weight_high_value1[i] > 1.02f * min_wt_cutoff1)
		{
			weight_high_value1[i] = 1.0f;
		}

		if (weight_high_value2[i] > 1.02f * min_wt_cutoff2)
		{
			weight_high_value2[i] = 1.0f;
		}

		// Compute weight bitcount for the mode
		unsigned int bits_used_by_weights = get_ise_sequence_bitcount(
		    2 * di.weight_count,
		    bm.get_weight_quant_mode());

		int bitcount = 113 - 4 - bits_used_by_weights;
		if (bitcount <= 0)
		{
			continue;
		}

		qwt_bitcounts[i] = bitcount;

		// Generate the optimized set of weights for the mode
		compute_quantized_weights_for_decimation(
		    di,
		    weight_low_value1[i],
		    weight_high_value1[i],
		    dec_weights_ideal_value + BLOCK_MAX_WEIGHTS * decimation_mode,
		    dec_weights_quant_uvalue + BLOCK_MAX_WEIGHTS * i,
		    dec_weights_quant_pvalue + BLOCK_MAX_WEIGHTS * i,
		    bm.get_weight_quant_mode());

		compute_quantized_weights_for_decimation(
		    di,
		    weight_low_value2[i],
		    weight_high_value2[i],
		    dec_weights_ideal_value + BLOCK_MAX_WEIGHTS * decimation_mode + WEIGHTS_PLANE2_OFFSET,
		    dec_weights_quant_uvalue + BLOCK_MAX_WEIGHTS * i + WEIGHTS_PLANE2_OFFSET,
		    dec_weights_quant_pvalue + BLOCK_MAX_WEIGHTS * i + WEIGHTS_PLANE2_OFFSET,
		    bm.get_weight_quant_mode());

		// Compute weight quantization errors for the block mode
		qwt_errors[i] = compute_error_of_weight_set_2planes(
		    eix1[decimation_mode],
		    eix2[decimation_mode],
		    di,
		    dec_weights_quant_uvalue + BLOCK_MAX_WEIGHTS * i,
		    dec_weights_quant_uvalue + BLOCK_MAX_WEIGHTS * i + WEIGHTS_PLANE2_OFFSET);
	}

	// Decide the optimal combination of color endpoint encodings and weight encodings
	int partition_format_specifiers[TUNE_MAX_TRIAL_CANDIDATES][BLOCK_MAX_PARTITIONS];
	int block_mode_index[TUNE_MAX_TRIAL_CANDIDATES];

	quant_method color_quant_level[TUNE_MAX_TRIAL_CANDIDATES];
	quant_method color_quant_level_mod[TUNE_MAX_TRIAL_CANDIDATES];

	endpoints epm;
	merge_endpoints(ei1.ep, ei2.ep, plane2_component, epm);

	const auto& pi = bsd.get_partition_info(1, 0);
	unsigned int candidate_count = compute_ideal_endpoint_formats(
	    bsd, pi, blk, ewb, epm, qwt_bitcounts, qwt_errors,
	    config.tune_candidate_limit, partition_format_specifiers, block_mode_index,
	    color_quant_level, color_quant_level_mod);

	// Iterate over the N believed-to-be-best modes to find out which one is actually best
	float best_errorval_in_mode = ERROR_CALC_DEFAULT;
	float best_errorval_in_scb = scb.errorval;

	for (unsigned int i = 0; i < candidate_count; i++)
	{
		TRACE_NODE(node0, "candidate");

		const int bm_packed_index = block_mode_index[i];
		assert(bm_packed_index >= 0 && bm_packed_index < (int)bsd.block_mode_count);
		const block_mode& qw_bm = bsd.block_modes[bm_packed_index];

		int decimation_mode = qw_bm.decimation_mode;
		int weight_quant_mode = qw_bm.quant_mode;
		const auto& di = bsd.get_decimation_info(decimation_mode);
		promise(di.weight_count > 0);

		trace_add_data("weight_x", di.weight_x);
		trace_add_data("weight_y", di.weight_y);
		trace_add_data("weight_z", di.weight_z);
		trace_add_data("weight_quant", weight_quant_mode);

		// Recompute the ideal color endpoints before storing them.
		merge_endpoints(eix1[decimation_mode].ep, eix2[decimation_mode].ep, plane2_component, epm);

		vfloat4 rgbs_color;
		vfloat4 rgbo_color;

		symbolic_compressed_block workscb;

		uint8_t* u8_weight1_src = dec_weights_quant_pvalue + BLOCK_MAX_WEIGHTS * bm_packed_index;
		uint8_t* u8_weight2_src = dec_weights_quant_pvalue + BLOCK_MAX_WEIGHTS * bm_packed_index + WEIGHTS_PLANE2_OFFSET;

		for (int j = 0; j < di.weight_count; j++)
		{
			workscb.weights[j] = u8_weight1_src[j];
			workscb.weights[j + WEIGHTS_PLANE2_OFFSET] = u8_weight2_src[j];
		}

		for (unsigned int l = 0; l < config.tune_refinement_limit; l++)
		{
			recompute_ideal_colors_2planes(
			    blk, ewb, bsd, di,
			    weight_quant_mode, workscb.weights, workscb.weights + WEIGHTS_PLANE2_OFFSET,
			    epm, rgbs_color, rgbo_color, plane2_component);

			// Quantize the chosen color
			workscb.color_formats[0] = pack_color_endpoints(
			                               epm.endpt0[0],
			                               epm.endpt1[0],
			                               rgbs_color, rgbo_color,
			                               partition_format_specifiers[i][0],
			                               workscb.color_values[0],
			                               (quant_method)color_quant_level[i]);

			// Store header fields
			workscb.partition_count = 1;
			workscb.partition_index = 0;
			workscb.quant_mode = color_quant_level[i];
			workscb.color_formats_matched = 0;
			workscb.block_mode = qw_bm.mode_index;
			workscb.plane2_component = static_cast<int8_t>(plane2_component);
			workscb.block_type = SYM_BTYPE_NONCONST;

			if (workscb.quant_mode < 4)
			{
				workscb.block_type = SYM_BTYPE_ERROR;
			}

			// Pre-realign test
			if (l == 0)
			{
				float errorval = compute_symbolic_block_difference(config, bsd, workscb, blk, ewb);
				if (errorval == -ERROR_CALC_DEFAULT)
				{
					errorval = -errorval;
					workscb.block_type = SYM_BTYPE_ERROR;
				}

				trace_add_data("error_prerealign", errorval);
				best_errorval_in_mode = astc::min(errorval, best_errorval_in_mode);

				// Average refinement improvement is 3.5% per iteration (allow 5%), but the first
				// iteration can help more so we give it a extra 10% leeway. Use this knowledge to
				// drive a heuristic to skip blocks that are unlikely to catch up with the best
				// block we have already.
				unsigned int iters_remaining = config.tune_refinement_limit - l;
				float threshold = (0.05f * static_cast<float>(iters_remaining)) + 1.1f;
				if (errorval > (threshold * best_errorval_in_scb))
				{
					break;
				}

				if (errorval < best_errorval_in_scb)
				{
					best_errorval_in_scb = errorval;
					workscb.errorval = errorval;
					scb = workscb;

					if (errorval < tune_errorval_threshold)
					{
						// Skip remaining candidates - this is "good enough"
						i = candidate_count;
						break;
					}
				}
			}

			// Perform a final pass over the weights to try to improve them
			bool adjustments = realign_weights(
			    config.profile, bsd, blk, ewb, workscb,
			    workscb.weights, workscb.weights + WEIGHTS_PLANE2_OFFSET);

			// Post-realign test
			float errorval = compute_symbolic_block_difference(config, bsd, workscb, blk, ewb);
			if (errorval == -ERROR_CALC_DEFAULT)
			{
				errorval = -errorval;
				workscb.block_type = SYM_BTYPE_ERROR;
			}

			trace_add_data("error_postrealign", errorval);
			best_errorval_in_mode = astc::min(errorval, best_errorval_in_mode);

			// Average refinement improvement is 3.5% per iteration, so skip blocks that are
			// unlikely to catch up with the best block we have already. Assume a 5% per step to
			// give benefit of the doubt ...
			unsigned int iters_remaining = config.tune_refinement_limit - 1 - l;
			float threshold = (0.05f * static_cast<float>(iters_remaining)) + 1.0f;
			if (errorval > (threshold * best_errorval_in_scb))
			{
				break;
			}

			if (errorval < best_errorval_in_scb)
			{
				best_errorval_in_scb = errorval;
				workscb.errorval = errorval;
				scb = workscb;

				if (errorval < tune_errorval_threshold)
				{
					// Skip remaining candidates - this is "good enough"
					i = candidate_count;
					break;
				}
			}

			if (!adjustments)
			{
				break;
			}
		}
	}

	return best_errorval_in_mode;
}