kevin知识库
首页 / MTK 平台 / /mtk/brightness-curve-adjustment/
整理中 创建 2026/06/06 更新 2026/06/06

路径如下:

#mtk #display

[MTK]亮度调整记录:压低高亮段峰值,保留中低亮手感

一、修改文件

路径如下:

kernel_device_modules-6.1/drivers/leds/leds-mtk.c

这次改动主要有三块:

新增一个高亮段重映射函数 brightness_remap_highlight()

brightness_maptolevel() 里接入这层 remap

mtk_leds_brightness_set() 里使用转换后的亮度值下发

二、先说结论:这次改的不是“亮度值”,而是“亮度曲线”

很多时候看 patch,第一眼会以为只是把最大亮度改小了。

其实不是。

这次的做法更像是:

  • 低亮到中亮:基本保持原来的线性关系
  • 高亮段:开始压缩
  • 满亮:不再直接冲到原始最大值,而是限制到一个更低的上限 也就是说,这不是简单粗暴地“整体变暗”。

而是做了一条分段映射曲线

这个思路在项目里很常见。

因为用户最敏感的,往往不是 10% 或 20% 的亮度。

而是 80% 往上那一段是不是太炸,是不是刺眼,是不是发热上来太快。

三、修改点 1:新增高亮压缩函数

新增代码如下:

staticintbrightness_remap_highlight(intlevel,intinput_max)
{
intknee;
intout_max;

if (level<=0||input_max<=0)
return0;

if (level>=input_max)
level=input_max;

/*
* Keep the lower 70% linear so normal indoor brightness feels the same,
* then compress the top-end to about 85.5% to reduce peak nits.
*/
knee=input_max*70/100;
out_max=input_max*830/1000;
if (out_max<=knee||input_max<=knee)
returnlevel;

if (level<=knee)
returnlevel;

returnknee+ (level-knee)* (out_max-knee)/
               (input_max-knee);
}

这段代码在干什么?

先说几个关键点:

1)knee 是拐点

knee=input_max*70/100;

这里把输入最大值的 70% 当成一个分界点。

含义很直接:

  • 0 ~ 70%:亮度不动,保持线性
  • 70% ~ 100%:开始压缩 这个思路挺稳。

因为室内常用亮度大多就在中低段。

把 70% 以下保持原样,用户平时手感基本不会变。

2)out_max 是压缩后的最高输出

out_max=input_max*830/1000;

这个值等于原始最大值的 83%

注意这里有个细节:

代码注释写的是:

compressthetop-endtoabout85.5%

但实际代码算出来是:

830/1000=83%

也就是说,注释和代码现在并不一致

真正生效的是代码,不是注释。

这一点发帖时最好写清。

不然后面别人照着看,会以为你压的是 85.5%,实际上你压的是 83%。

3)70% 以下不变,70% 以上重新拉一条线

如果亮度还没到 knee

if (level<=knee)
returnlevel;

那就原样返回。

不做任何处理。

如果超过了 knee,就用下面这条公式重新映射:

returnknee+ (level-knee)* (out_max-knee)/
       (input_max-knee);

这个公式本质上就是:

把原来 [70%, 100%] 这一段,线性压缩到 [70%, 83%] 这一段。

所以最终效果就是:

  • 中低亮不变
  • 高亮越来越“收”
  • 满亮不再顶到最上面

四、修改点 2:在 brightness_maptolevel() 里接入 remap

改动前:

staticintbrightness_maptolevel(structled_conf_info*led_conf,intbrightness)
{
return (((led_conf->max_hw_brightness)*brightness
+ ((led_conf->cdev.max_brightness)/2))
/ (led_conf->cdev.max_brightness));
}

改动后:

staticintbrightness_maptolevel(structled_conf_info*led_conf,intbrightness)
{
intlevel;

level= (((led_conf->max_hw_brightness)*brightness
+ ((led_conf->cdev.max_brightness)/2))
/ (led_conf->cdev.max_brightness));

returnbrightness_remap_highlight(level,led_conf->max_hw_brightness);
}

这里的变化很关键

原来这函数只做一件事:

把上层传下来的亮度值,按比例映射到硬件亮度范围。

比如:

  • Android 亮度是 0 ~ 2047
  • 硬件亮度是 0 ~ 4095 那这里就是做一次普通线性缩放。

现在多了一步:

  • 先做原始线性映射
  • 再做高亮段压缩 也就是说,从这个函数返回出去的值,已经不是“纯线性结果”了。

而是带曲线修正后的硬件亮度值

这一步一接进去,整个背光输出逻辑就变了。

不是局部修一下。

而是把高亮段整体重塑了。


五、修改点 3:在 mtk_leds_brightness_set() 里下发转换后的亮度

改动如下:

intmtk_leds_brightness_set(intconnector_id,intlevel,
{
structmt_led_data*led_dat;
intindex;
inttrans_level;

       ...

if (!led_dat->conf.aal_enable) {
//pr_debug("aal not enable, set %s %d return", name, level);
       }else {
trans_level=brightness_maptolevel(&led_dat->conf,level);
mtk_set_hw_brightness(led_dat,trans_level,params,params_flag);
led_dat->last_hw_brightness=trans_level;
       }

       ...
}

这里要看两个点

1)增加了 trans_level

这个变量名字起得还可以。

意思很直接,就是:

把用户输入亮度转换后的实际下发值。

所以这里已经不是直接拿 level 往下写了。

而是先过一遍 brightness_maptolevel(),再写给硬件。

2)last_hw_brightness 记录的也变了

原来是:

led_dat->last_hw_brightness=level;

现在变成:

led_dat->last_hw_brightness=trans_level;

这个变化不大,但语义变了。

原来它记的更像是“请求亮度”。

现在它记的是“实际硬件亮度”。

这点挺重要。

因为后面如果有人拿 last_hw_brightness 做日志、对比、补偿或者恢复,就要知道它现在存的是转换后的值,不是原始输入值。