brintos

brintos / linux-shallow public Read only

0
0
Text · 18.7 KiB · f31f0e3 Raw
613 lines · c
1/*2 * Copyright 2020 Advanced Micro Devices, Inc.3 *4 * Permission is hereby granted, free of charge, to any person obtaining a5 * copy of this software and associated documentation files (the "Software"),6 * to deal in the Software without restriction, including without limitation7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,8 * and/or sell copies of the Software, and to permit persons to whom the9 * Software is furnished to do so, subject to the following conditions:10 *11 * The above copyright notice and this permission notice shall be included in12 * all copies or substantial portions of the Software.13 *14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR20 * OTHER DEALINGS IN THE SOFTWARE.21 *22 * Authors: AMD23 *24 */25 26#include "dm_services.h"27#include "core_types.h"28#include "reg_helper.h"29#include "dcn30/dcn30_dpp.h"30#include "basics/conversion.h"31#include "dcn30/dcn30_cm_common.h"32#include "custom_float.h"33 34#define REG(reg) reg35 36#define CTX \37	ctx //dpp->base.ctx38 39#undef FN40#define FN(reg_name, field_name) \41	reg->shifts.field_name, reg->masks.field_name42 43void cm_helper_program_gamcor_xfer_func(44		struct dc_context *ctx,45		const struct pwl_params *params,46		const struct dcn3_xfer_func_reg *reg)47{48	uint32_t reg_region_cur;49	unsigned int i = 0;50 51	REG_SET_2(reg->start_cntl_b, 0,52		exp_region_start, params->corner_points[0].blue.custom_float_x,53		exp_resion_start_segment, 0);54	REG_SET_2(reg->start_cntl_g, 0,55		exp_region_start, params->corner_points[0].green.custom_float_x,56		exp_resion_start_segment, 0);57	REG_SET_2(reg->start_cntl_r, 0,58		exp_region_start, params->corner_points[0].red.custom_float_x,59		exp_resion_start_segment, 0);60 61	REG_SET(reg->start_slope_cntl_b, 0, //linear slope at start of curve62		field_region_linear_slope, params->corner_points[0].blue.custom_float_slope);63	REG_SET(reg->start_slope_cntl_g, 0,64		field_region_linear_slope, params->corner_points[0].green.custom_float_slope);65	REG_SET(reg->start_slope_cntl_r, 0,66		field_region_linear_slope, params->corner_points[0].red.custom_float_slope);67 68	REG_SET(reg->start_end_cntl1_b, 0,69		field_region_end_base, params->corner_points[1].blue.custom_float_y);70	REG_SET(reg->start_end_cntl1_g, 0,71		field_region_end_base, params->corner_points[1].green.custom_float_y);72	REG_SET(reg->start_end_cntl1_r, 0,73		field_region_end_base, params->corner_points[1].red.custom_float_y);74 75	REG_SET_2(reg->start_end_cntl2_b, 0,76		field_region_end_slope, params->corner_points[1].blue.custom_float_slope,77		field_region_end, params->corner_points[1].blue.custom_float_x);78	REG_SET_2(reg->start_end_cntl2_g, 0,79		field_region_end_slope, params->corner_points[1].green.custom_float_slope,80		field_region_end, params->corner_points[1].green.custom_float_x);81	REG_SET_2(reg->start_end_cntl2_r, 0,82		field_region_end_slope, params->corner_points[1].red.custom_float_slope,83		field_region_end, params->corner_points[1].red.custom_float_x);84 85	for (reg_region_cur = reg->region_start;86		reg_region_cur <= reg->region_end;87		reg_region_cur++) {88 89		const struct gamma_curve *curve0 = &(params->arr_curve_points[2 * i]);90		const struct gamma_curve *curve1 = &(params->arr_curve_points[(2 * i) + 1]);91 92		REG_SET_4(reg_region_cur, 0,93			exp_region0_lut_offset, curve0->offset,94			exp_region0_num_segments, curve0->segments_num,95			exp_region1_lut_offset, curve1->offset,96			exp_region1_num_segments, curve1->segments_num);97 98		i++;99	}100}101 102/* driver uses 32 regions or less, but DCN HW has 34, extra 2 are set to 0 */103#define MAX_REGIONS_NUMBER 34104#define MAX_LOW_POINT      25105#define NUMBER_REGIONS     32106#define NUMBER_SW_SEGMENTS 16107 108bool cm3_helper_translate_curve_to_hw_format(109				const struct dc_transfer_func *output_tf,110				struct pwl_params *lut_params, bool fixpoint)111{112	struct curve_points3 *corner_points;113	struct pwl_result_data *rgb_resulted;114	struct pwl_result_data *rgb;115	struct pwl_result_data *rgb_plus_1;116	struct pwl_result_data *rgb_minus_1;117 118	int32_t region_start, region_end;119	int32_t i;120	uint32_t j, k, seg_distr[MAX_REGIONS_NUMBER], increment, start_index, hw_points;121 122	if (output_tf == NULL || lut_params == NULL || output_tf->type == TF_TYPE_BYPASS)123		return false;124 125	corner_points = lut_params->corner_points;126	rgb_resulted = lut_params->rgb_resulted;127	hw_points = 0;128 129	memset(lut_params, 0, sizeof(struct pwl_params));130	memset(seg_distr, 0, sizeof(seg_distr));131 132	if (output_tf->tf == TRANSFER_FUNCTION_PQ || output_tf->tf == TRANSFER_FUNCTION_GAMMA22 ||133		output_tf->tf == TRANSFER_FUNCTION_HLG) {134		/* 32 segments135		 * segments are from 2^-25 to 2^7136		 */137		for (i = 0; i < NUMBER_REGIONS ; i++)138			seg_distr[i] = 3;139 140		region_start = -MAX_LOW_POINT;141		region_end   = NUMBER_REGIONS - MAX_LOW_POINT;142	} else {143		/* 11 segments144		 * segment is from 2^-10 to 2^0145		 * There are less than 256 points, for optimization146		 */147		seg_distr[0] = 3;148		seg_distr[1] = 4;149		seg_distr[2] = 4;150		seg_distr[3] = 4;151		seg_distr[4] = 4;152		seg_distr[5] = 4;153		seg_distr[6] = 4;154		seg_distr[7] = 4;155		seg_distr[8] = 4;156		seg_distr[9] = 4;157		seg_distr[10] = 1;158 159		region_start = -10;160		region_end = 1;161	}162 163	for (i = region_end - region_start; i < MAX_REGIONS_NUMBER ; i++)164		seg_distr[i] = -1;165 166	for (k = 0; k < MAX_REGIONS_NUMBER; k++) {167		if (seg_distr[k] != -1)168			hw_points += (1 << seg_distr[k]);169	}170 171	j = 0;172	for (k = 0; k < (region_end - region_start); k++) {173		increment = NUMBER_SW_SEGMENTS / (1 << seg_distr[k]);174		start_index = (region_start + k + MAX_LOW_POINT) *175				NUMBER_SW_SEGMENTS;176		for (i = start_index; i < start_index + NUMBER_SW_SEGMENTS;177				i += increment) {178			if (j == hw_points)179				break;180			if (i >= TRANSFER_FUNC_POINTS)181				return false;182			rgb_resulted[j].red = output_tf->tf_pts.red[i];183			rgb_resulted[j].green = output_tf->tf_pts.green[i];184			rgb_resulted[j].blue = output_tf->tf_pts.blue[i];185			j++;186		}187	}188 189	/* last point */190	start_index = (region_end + MAX_LOW_POINT) * NUMBER_SW_SEGMENTS;191	rgb_resulted[hw_points].red = output_tf->tf_pts.red[start_index];192	rgb_resulted[hw_points].green = output_tf->tf_pts.green[start_index];193	rgb_resulted[hw_points].blue = output_tf->tf_pts.blue[start_index];194 195	rgb_resulted[hw_points+1].red = rgb_resulted[hw_points].red;196	rgb_resulted[hw_points+1].green = rgb_resulted[hw_points].green;197	rgb_resulted[hw_points+1].blue = rgb_resulted[hw_points].blue;198 199	// All 3 color channels have same x200	corner_points[0].red.x = dc_fixpt_pow(dc_fixpt_from_int(2),201					     dc_fixpt_from_int(region_start));202	corner_points[0].green.x = corner_points[0].red.x;203	corner_points[0].blue.x = corner_points[0].red.x;204 205	corner_points[1].red.x = dc_fixpt_pow(dc_fixpt_from_int(2),206					     dc_fixpt_from_int(region_end));207	corner_points[1].green.x = corner_points[1].red.x;208	corner_points[1].blue.x = corner_points[1].red.x;209 210	corner_points[0].red.y = rgb_resulted[0].red;211	corner_points[0].green.y = rgb_resulted[0].green;212	corner_points[0].blue.y = rgb_resulted[0].blue;213 214	corner_points[0].red.slope = dc_fixpt_div(corner_points[0].red.y,215			corner_points[0].red.x);216	corner_points[0].green.slope = dc_fixpt_div(corner_points[0].green.y,217			corner_points[0].green.x);218	corner_points[0].blue.slope = dc_fixpt_div(corner_points[0].blue.y,219			corner_points[0].blue.x);220 221	/* see comment above, m_arrPoints[1].y should be the Y value for the222	 * region end (m_numOfHwPoints), not last HW point(m_numOfHwPoints - 1)223	 */224	corner_points[1].red.y = rgb_resulted[hw_points].red;225	corner_points[1].green.y = rgb_resulted[hw_points].green;226	corner_points[1].blue.y = rgb_resulted[hw_points].blue;227	corner_points[1].red.slope = dc_fixpt_zero;228	corner_points[1].green.slope = dc_fixpt_zero;229	corner_points[1].blue.slope = dc_fixpt_zero;230 231	// DCN3+ have 257 pts in lieu of no separate slope registers232	// Prior HW had 256 base+slope pairs233	lut_params->hw_points_num = hw_points + 1;234 235	k = 0;236	for (i = 1; i < MAX_REGIONS_NUMBER; i++) {237		if (seg_distr[k] != -1) {238			lut_params->arr_curve_points[k].segments_num =239					seg_distr[k];240			lut_params->arr_curve_points[i].offset =241					lut_params->arr_curve_points[k].offset + (1 << seg_distr[k]);242		}243		k++;244	}245 246	if (seg_distr[k] != -1)247		lut_params->arr_curve_points[k].segments_num = seg_distr[k];248 249	rgb = rgb_resulted;250	rgb_plus_1 = rgb_resulted + 1;251	rgb_minus_1 = rgb;252 253	if (fixpoint == true) {254		i = 1;255		while (i != hw_points + 2) {256			if (i >= hw_points) {257				if (dc_fixpt_lt(rgb_plus_1->red, rgb->red))258					rgb_plus_1->red = dc_fixpt_add(rgb->red,259							rgb_minus_1->delta_red);260				if (dc_fixpt_lt(rgb_plus_1->green, rgb->green))261					rgb_plus_1->green = dc_fixpt_add(rgb->green,262							rgb_minus_1->delta_green);263				if (dc_fixpt_lt(rgb_plus_1->blue, rgb->blue))264					rgb_plus_1->blue = dc_fixpt_add(rgb->blue,265							rgb_minus_1->delta_blue);266			}267 268			rgb->delta_red_reg   = dc_fixpt_clamp_u0d10(rgb->delta_red);269			rgb->delta_green_reg = dc_fixpt_clamp_u0d10(rgb->delta_green);270			rgb->delta_blue_reg  = dc_fixpt_clamp_u0d10(rgb->delta_blue);271			rgb->red_reg         = dc_fixpt_clamp_u0d14(rgb->red);272			rgb->green_reg       = dc_fixpt_clamp_u0d14(rgb->green);273			rgb->blue_reg        = dc_fixpt_clamp_u0d14(rgb->blue);274 275			++rgb_plus_1;276			rgb_minus_1 = rgb;277			++rgb;278			++i;279		}280	}281	cm3_helper_convert_to_custom_float(rgb_resulted,282						lut_params->corner_points,283						hw_points+1, fixpoint);284 285	return true;286}287 288#define NUM_DEGAMMA_REGIONS    12289 290 291bool cm3_helper_translate_curve_to_degamma_hw_format(292				const struct dc_transfer_func *output_tf,293				struct pwl_params *lut_params)294{295	struct curve_points3 *corner_points;296	struct pwl_result_data *rgb_resulted;297	struct pwl_result_data *rgb;298	struct pwl_result_data *rgb_plus_1;299 300	int32_t region_start, region_end;301	int32_t i;302	uint32_t j, k, seg_distr[MAX_REGIONS_NUMBER], increment, start_index, hw_points;303 304	if (output_tf == NULL || lut_params == NULL || output_tf->type == TF_TYPE_BYPASS)305		return false;306 307	corner_points = lut_params->corner_points;308	rgb_resulted = lut_params->rgb_resulted;309	hw_points = 0;310 311	memset(lut_params, 0, sizeof(struct pwl_params));312	memset(seg_distr, 0, sizeof(seg_distr));313 314	region_start = -NUM_DEGAMMA_REGIONS;315	region_end   = 0;316 317 318	for (i = region_end - region_start; i < MAX_REGIONS_NUMBER ; i++)319		seg_distr[i] = -1;320	/* 12 segments321	 * segments are from 2^-12 to 0322	 */323	for (i = 0; i < NUM_DEGAMMA_REGIONS ; i++)324		seg_distr[i] = 4;325 326	for (k = 0; k < MAX_REGIONS_NUMBER; k++) {327		if (seg_distr[k] != -1)328			hw_points += (1 << seg_distr[k]);329	}330 331	j = 0;332	for (k = 0; k < (region_end - region_start); k++) {333		increment = NUMBER_SW_SEGMENTS / (1 << seg_distr[k]);334		start_index = (region_start + k + MAX_LOW_POINT) *335				NUMBER_SW_SEGMENTS;336		for (i = start_index; i < start_index + NUMBER_SW_SEGMENTS;337				i += increment) {338			if (j == hw_points - 1)339				break;340			if (i >= TRANSFER_FUNC_POINTS)341				return false;342			rgb_resulted[j].red = output_tf->tf_pts.red[i];343			rgb_resulted[j].green = output_tf->tf_pts.green[i];344			rgb_resulted[j].blue = output_tf->tf_pts.blue[i];345			j++;346		}347	}348 349	/* last point */350	start_index = (region_end + MAX_LOW_POINT) * NUMBER_SW_SEGMENTS;351	rgb_resulted[hw_points - 1].red = output_tf->tf_pts.red[start_index];352	rgb_resulted[hw_points - 1].green = output_tf->tf_pts.green[start_index];353	rgb_resulted[hw_points - 1].blue = output_tf->tf_pts.blue[start_index];354 355	corner_points[0].red.x = dc_fixpt_pow(dc_fixpt_from_int(2),356					     dc_fixpt_from_int(region_start));357	corner_points[0].green.x = corner_points[0].red.x;358	corner_points[0].blue.x = corner_points[0].red.x;359	corner_points[1].red.x = dc_fixpt_pow(dc_fixpt_from_int(2),360					     dc_fixpt_from_int(region_end));361	corner_points[1].green.x = corner_points[1].red.x;362	corner_points[1].blue.x = corner_points[1].red.x;363 364	corner_points[0].red.y = rgb_resulted[0].red;365	corner_points[0].green.y = rgb_resulted[0].green;366	corner_points[0].blue.y = rgb_resulted[0].blue;367 368	/* see comment above, m_arrPoints[1].y should be the Y value for the369	 * region end (m_numOfHwPoints), not last HW point(m_numOfHwPoints - 1)370	 */371	corner_points[1].red.y = rgb_resulted[hw_points - 1].red;372	corner_points[1].green.y = rgb_resulted[hw_points - 1].green;373	corner_points[1].blue.y = rgb_resulted[hw_points - 1].blue;374	corner_points[1].red.slope = dc_fixpt_zero;375	corner_points[1].green.slope = dc_fixpt_zero;376	corner_points[1].blue.slope = dc_fixpt_zero;377 378	if (output_tf->tf == TRANSFER_FUNCTION_PQ) {379		/* for PQ, we want to have a straight line from last HW X point,380		 * and the slope to be such that we hit 1.0 at 10000 nits.381		 */382		const struct fixed31_32 end_value =383				dc_fixpt_from_int(125);384 385		corner_points[1].red.slope = dc_fixpt_div(386			dc_fixpt_sub(dc_fixpt_one, corner_points[1].red.y),387			dc_fixpt_sub(end_value, corner_points[1].red.x));388		corner_points[1].green.slope = dc_fixpt_div(389			dc_fixpt_sub(dc_fixpt_one, corner_points[1].green.y),390			dc_fixpt_sub(end_value, corner_points[1].green.x));391		corner_points[1].blue.slope = dc_fixpt_div(392			dc_fixpt_sub(dc_fixpt_one, corner_points[1].blue.y),393			dc_fixpt_sub(end_value, corner_points[1].blue.x));394	}395 396	lut_params->hw_points_num = hw_points;397 398	k = 0;399	for (i = 1; i < MAX_REGIONS_NUMBER; i++) {400		if (seg_distr[k] != -1) {401			lut_params->arr_curve_points[k].segments_num =402					seg_distr[k];403			lut_params->arr_curve_points[i].offset =404					lut_params->arr_curve_points[k].offset + (1 << seg_distr[k]);405		}406		k++;407	}408 409	if (seg_distr[k] != -1)410		lut_params->arr_curve_points[k].segments_num = seg_distr[k];411 412	rgb = rgb_resulted;413	rgb_plus_1 = rgb_resulted + 1;414 415	i = 1;416	while (i != hw_points + 1) {417		if (dc_fixpt_lt(rgb_plus_1->red, rgb->red))418			rgb_plus_1->red = rgb->red;419		if (dc_fixpt_lt(rgb_plus_1->green, rgb->green))420			rgb_plus_1->green = rgb->green;421		if (dc_fixpt_lt(rgb_plus_1->blue, rgb->blue))422			rgb_plus_1->blue = rgb->blue;423 424		rgb->delta_red   = dc_fixpt_sub(rgb_plus_1->red,   rgb->red);425		rgb->delta_green = dc_fixpt_sub(rgb_plus_1->green, rgb->green);426		rgb->delta_blue  = dc_fixpt_sub(rgb_plus_1->blue,  rgb->blue);427 428		++rgb_plus_1;429		++rgb;430		++i;431	}432	cm3_helper_convert_to_custom_float(rgb_resulted,433						lut_params->corner_points,434						hw_points, false);435 436	return true;437}438 439bool cm3_helper_convert_to_custom_float(440		struct pwl_result_data *rgb_resulted,441		struct curve_points3 *corner_points,442		uint32_t hw_points_num,443		bool fixpoint)444{445	struct custom_float_format fmt;446 447	struct pwl_result_data *rgb = rgb_resulted;448 449	uint32_t i = 0;450 451	fmt.exponenta_bits = 6;452	fmt.mantissa_bits = 12;453	fmt.sign = false;454 455	/* corner_points[0] - beginning base, slope offset for R,G,B456	 * corner_points[1] - end base, slope offset for R,G,B457	 */458	if (!convert_to_custom_float_format(corner_points[0].red.x, &fmt,459				&corner_points[0].red.custom_float_x)) {460		BREAK_TO_DEBUGGER();461		return false;462	}463	if (!convert_to_custom_float_format(corner_points[0].green.x, &fmt,464				&corner_points[0].green.custom_float_x)) {465		BREAK_TO_DEBUGGER();466		return false;467	}468	if (!convert_to_custom_float_format(corner_points[0].blue.x, &fmt,469				&corner_points[0].blue.custom_float_x)) {470		BREAK_TO_DEBUGGER();471		return false;472	}473 474	if (!convert_to_custom_float_format(corner_points[0].red.offset, &fmt,475				&corner_points[0].red.custom_float_offset)) {476		BREAK_TO_DEBUGGER();477		return false;478	}479	if (!convert_to_custom_float_format(corner_points[0].green.offset, &fmt,480				&corner_points[0].green.custom_float_offset)) {481		BREAK_TO_DEBUGGER();482		return false;483	}484	if (!convert_to_custom_float_format(corner_points[0].blue.offset, &fmt,485				&corner_points[0].blue.custom_float_offset)) {486		BREAK_TO_DEBUGGER();487		return false;488	}489 490	if (!convert_to_custom_float_format(corner_points[0].red.slope, &fmt,491				&corner_points[0].red.custom_float_slope)) {492		BREAK_TO_DEBUGGER();493		return false;494	}495	if (!convert_to_custom_float_format(corner_points[0].green.slope, &fmt,496				&corner_points[0].green.custom_float_slope)) {497		BREAK_TO_DEBUGGER();498		return false;499	}500	if (!convert_to_custom_float_format(corner_points[0].blue.slope, &fmt,501				&corner_points[0].blue.custom_float_slope)) {502		BREAK_TO_DEBUGGER();503		return false;504	}505 506	if (fixpoint == true) {507		corner_points[1].red.custom_float_y =508				dc_fixpt_clamp_u0d14(corner_points[1].red.y);509		corner_points[1].green.custom_float_y =510				dc_fixpt_clamp_u0d14(corner_points[1].green.y);511		corner_points[1].blue.custom_float_y =512				dc_fixpt_clamp_u0d14(corner_points[1].blue.y);513	} else {514		if (!convert_to_custom_float_format(corner_points[1].red.y,515				&fmt, &corner_points[1].red.custom_float_y)) {516			BREAK_TO_DEBUGGER();517			return false;518		}519		if (!convert_to_custom_float_format(corner_points[1].green.y,520				&fmt, &corner_points[1].green.custom_float_y)) {521			BREAK_TO_DEBUGGER();522			return false;523		}524		if (!convert_to_custom_float_format(corner_points[1].blue.y,525				&fmt, &corner_points[1].blue.custom_float_y)) {526			BREAK_TO_DEBUGGER();527			return false;528		}529	}530 531	fmt.mantissa_bits = 10;532	fmt.sign = false;533 534	if (!convert_to_custom_float_format(corner_points[1].red.x, &fmt,535				&corner_points[1].red.custom_float_x)) {536		BREAK_TO_DEBUGGER();537		return false;538	}539	if (!convert_to_custom_float_format(corner_points[1].green.x, &fmt,540				&corner_points[1].green.custom_float_x)) {541		BREAK_TO_DEBUGGER();542		return false;543	}544	if (!convert_to_custom_float_format(corner_points[1].blue.x, &fmt,545				&corner_points[1].blue.custom_float_x)) {546		BREAK_TO_DEBUGGER();547		return false;548	}549 550	if (!convert_to_custom_float_format(corner_points[1].red.slope, &fmt,551				&corner_points[1].red.custom_float_slope)) {552		BREAK_TO_DEBUGGER();553		return false;554	}555	if (!convert_to_custom_float_format(corner_points[1].green.slope, &fmt,556				&corner_points[1].green.custom_float_slope)) {557		BREAK_TO_DEBUGGER();558		return false;559	}560	if (!convert_to_custom_float_format(corner_points[1].blue.slope, &fmt,561				&corner_points[1].blue.custom_float_slope)) {562		BREAK_TO_DEBUGGER();563		return false;564	}565 566	if (hw_points_num == 0 || rgb_resulted == NULL || fixpoint == true)567		return true;568 569	fmt.mantissa_bits = 12;570 571	while (i != hw_points_num) {572		if (!convert_to_custom_float_format(rgb->red, &fmt,573						    &rgb->red_reg)) {574			BREAK_TO_DEBUGGER();575			return false;576		}577 578		if (!convert_to_custom_float_format(rgb->green, &fmt,579						    &rgb->green_reg)) {580			BREAK_TO_DEBUGGER();581			return false;582		}583 584		if (!convert_to_custom_float_format(rgb->blue, &fmt,585						    &rgb->blue_reg)) {586			BREAK_TO_DEBUGGER();587			return false;588		}589 590		++rgb;591		++i;592	}593 594	return true;595}596 597bool is_rgb_equal(const struct pwl_result_data *rgb, uint32_t num)598{599	uint32_t i;600	bool ret = true;601 602	for (i = 0 ; i < num; i++) {603		if (rgb[i].red_reg != rgb[i].green_reg ||604		rgb[i].blue_reg != rgb[i].red_reg  ||605		rgb[i].blue_reg != rgb[i].green_reg) {606			ret = false;607			break;608		}609	}610	return ret;611}612 613