整理中 创建 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` 做日志、对比、补偿或者恢复,就要知道它现在存的是**转换后的值**,不是原始输入值。

---