总述

前段时间在一个项目里,做了一个色温调节的东西。发现这部分的资料有点少,所幸研究了一段时间,记录一下,免得后面又忘记了。
色温调节是上层发出,最终由显卡驱动处理的一个事件。桌面一般都是采用redshift 调节色温,到xserver,xserver进行一些自己的处理,转由libdrm用drm ioctl陷入内核drm模块,最终到实际的显卡驱动。redshift这边没怎么研究过,本文就先从xserver讲起吧。涉及到具体的显卡驱动,就用radeon驱动为例。

xserver

用户可以直接用xrand命令调节色温:

xrandr --output XXXX --gamma 1:1:1

可以用这个命令看看色温调节是否正常。
gamma参数后面第一个1是红色,第二个1是绿色,第三个1是蓝色。通过调三原色达到调色温的目的。先拉一份xserver的代码来看看xserver是怎么处理参数的。从debian的仓库里直接拉下,非常方便。apt source xorg-server(不要用sudo拉代码,不信你可以试试看)。经验之谈:代码拉下来之后,先打个包替换本地安装的xserver,验证代码的正确性。
dpkg-buildpackage -sa -nc -j40,第一次打包会很慢,稍微等一会。完成之后会在父目录下生成很多个deb包,暂时没分辨分别是什么什么包,所以统统安装,之后重启xserver。重启之后x依然运行正常,那就没什么问题了。
对于xserver而言,上层可以通过两种方式调节色温:一种是redshift;另一种是xrandr提供的gamma参数。这两种方式一开始调用的接口不同,殊途同归,最终通过同一个接口进到libdrm中去。

redshift调节色温xserver函数调用链

ProcVidModeSetGamma
{if (!pVidMode->SetGamma(pScreen, ((float) stuff->red) / 10000.,((float) stuff->green) / 10000.,((float) stuff->blue) / 10000.))return BadValue;return Success;
}->xf86VidModeSetGamma->xf86ChangeGamma->CMapChangeGamma->CMapReinstallMap->CMapRefreshColors->xf86RandR12LoadPalette{for (c = 0; c < config->num_crtc; c++) {xf86CrtcPtr crtc = config->crtc[c];RRCrtcPtr randr_crtc = crtc->randr_crtc;if (randr_crtc) {xf86RandR12CrtcComputeGamma(crtc, colors, reds, greens, blues,randr_crtc->gammaRed,randr_crtc->gammaGreen,randr_crtc->gammaBlue,randr_crtc->gammaSize);} else {xf86RandR12CrtcComputeGamma(crtc, colors, reds, greens, blues,NULL, NULL, NULL,xf86GetGammaRampSize(pScreen));}xf86RandR12CrtcReloadGamma(crtc);}}->xf86RandR12CrtcReloadGamma->drmmode_crtc_gamma_set{drmModeCrtcSetGamma(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,size, red, green, blue);}

xf86VidModeSetGammaProcVidModeSetGamma接口实现在x扩展中,应该和x协议 xclient有关(细节待补充)。这个函数根据传入的参数,调用实现在xf86中的setgamma钩子函数,钩子上挂的是xf86VidModeSetGamma,这个函数没什么实际功能是个框架:转换参数,调用xf86ChangeGamma->CMapChangeGamma->``CMapReinstallMap->CMapRefreshColors->xf86RandR12LoadPalettexf86RandR12LoadPalette遍历每个crtc,分别计算gamma和load gamma。 用户可能修改一个或者多个gamma参数,在这里全部扫过之后,可以节省调用时间。 load gamma直接调用crtc的gamma set接口——drmmode_crtc_gamma_set,从这里正式进入libdrm里。
xrandr方式调节色温的调用链简单多了,从randr调用带xf86中,余下的和上面一样。

RRCrtcGammaSet->xf86RandR12CrtcSetGamma->xf86RandR12CrtcReloadGamma->drmmode_crtc_gamma_set

libdrm

令人迷惑的xserver终于大概理清楚了,主要是能力有限,分析不清楚。libdrm的代码一般都很简单,做一个基本的判非操作之后,用ioctl陷入内核中。比如刚刚找不到的 函数,他的实现是这样的:

drm_public int drmModeCrtcSetGamma(int fd, uint32_t crtc_id, uint32_t size,uint16_t *red, uint16_t *green,uint16_t *blue){struct drm_mode_crtc_lut l;memclear(l);l.crtc_id = crtc_id;l.gamma_size = size;l.red = VOID2U64(red);l.green = VOID2U64(green);l.blue = VOID2U64(blue);return DRM_IOCTL(fd, DRM_IOCTL_MODE_SETGAMMA, &l);}

熟悉内核代码的童鞋都知道,从ioctl开始就陷入内核了。接下来需要去drm驱动里找到对DRM_IOCTL_MODE_SETGAMMAflag的处理即可。

内核drm模块

drm 的ioctl接口都是实现在文件drivers/gpu/drm/drm_ioctl.c中,DRM_IOCTL_MODE_SETGAMMA对应的接口是drm_mode_gamma_set_ioctl

int drm_mode_gamma_set_ioctl(struct drm_device *dev,void *data, struct drm_file *file_priv)
{struct drm_mode_crtc_lut *crtc_lut = data;struct drm_crtc *crtc;void *r_base, *g_base, *b_base;int size;struct drm_modeset_acquire_ctx ctx;int ret = 0;if (!drm_core_check_feature(dev, DRIVER_MODESET))return -EINVAL;crtc = drm_crtc_find(dev, file_priv, crtc_lut->crtc_id);if (!crtc)return -ENOENT;if (crtc->funcs->gamma_set == NULL)return -ENOSYS;drm_modeset_acquire_init(&ctx, 0);
retry:ret = drm_modeset_lock_all_ctx(dev, &ctx);if (ret)goto out;size = crtc_lut->gamma_size * (sizeof(uint16_t));r_base = crtc->gamma_store;if (copy_from_user(r_base, (void __user *)(unsigned long)crtc_lut->red, size)) {ret = -EFAULT;goto out;}g_base = r_base + size;if (copy_from_user(g_base, (void __user *)(unsigned long)crtc_lut->green, size)) {ret = -EFAULT;goto out;}b_base = g_base + size;if (copy_from_user(b_base, (void __user *)(unsigned long)crtc_lut->blue, size)) {ret = -EFAULT;goto out;}ret = crtc->funcs->gamma_set(crtc, r_base, g_base, b_base,crtc->gamma_size, &ctx);
......return ret;
}

按照惯例,drm只实现框架代码并不care具体的功能,代码通常比较简单,没什么复杂的调用链。drm进来先判断操作的合法性,检查feature标志、根据用户参数获取crtc,判断显卡是否实现了gamma_set接口。全部正常之后,根据用户传入的参数计算红绿蓝三色的基准值,然后调用显卡自己实现的gamma_set接口。以radeon为例,大致调用链如下所示:

radeon_crtc_gamma_set->radeon_crtc_load_lut{
#define ASIC_IS_DCE5(rdev) ((rdev->family >= CHIP_BARTS))if (ASIC_IS_DCE5(rdev))dce5_crtc_load_lut(crtc);else if (ASIC_IS_DCE4(rdev))dce4_crtc_load_lut(crtc);else if (ASIC_IS_AVIVO(rdev))avivo_crtc_load_lut(crtc);elselegacy_crtc_load_lut(crtc);}->device dependence write registers

radeon gamma_set调用radeon_crtc_load_lut,load lut根据显卡芯片类型确定调用哪个,在load lut中实现写寄存器,这部分就和硬件相关了。不同的显卡芯片、不同给厂家的显卡,这部分实现都是不一样的。

Q & A

    1. 为什么有的设备能调节色温,有的设备不能调节色温呢?
      色温调节是要显卡支持的,如上分析,色温调节最终从drm 的gamma_set调用到显卡自身实现的gamma_set中去,真正执行调节功能的是显卡自身的gamma set函数。然而不是所有得到显卡都实现了这个功能,因此给用户看到的现象是:有的卡能调色温,有的卡不支持。

当我们在谈论色温调节的时候,我们在谈论什么相关推荐

  1. 支持色温调节 新款Kindle Oasia上市 国行版售价2399元起

    今日,亚马逊宣布推出全新Kindle Oasis电子书阅读器.全新Kindle Oasis配备7英寸300ppi超清屏幕,使用全新一代电子墨水技术,新增暖光阅读灯,支持冷暖色温调节,更可感应环境光线智 ...

  2. Ubuntu(护眼设置)安装屏幕色温调节软件F.lux

    CSDN GitHub Ubuntu(护眼设置)安装屏幕色温调节软件F.lux AderXCoding/system/tools/flux 本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 ...

  3. Ubuntu16.04安装Redshift色温调节工具

    Only I can change my life, No one can do it for me. 除了为没有人能够改变我的命运. Ubuntu16.04安装Redshift色温调节工具 以前一直 ...

  4. NanoPC-T4|Android-Q 色温调节

    0 前言 Android手机都支持色温调节,但这并非Android原生功能,本文基于NanoPC-T4分析具体应如何实现该功能. Tips:可根据参考资料[1]的12.3.1小节"下载And ...

  5. kindle如何设置不闪屏_Nook GlowLight 3低调现身 色温调节和不闪屏能否打破Kindle垄断?...

    不知大家是否还记得Nook?它是美国图书零售商Barnes & Noble旗下的电纸书品牌,发布了新款带有夜间模式的GlowLight 3.而Nook的上一款电纸书产品还是15年发售的Glow ...

  6. 当顶流厂商谈论智能手表,他们到底在谈论什么

    伊瓢 雷刚 发自 凹非寺 量子位 报道 | 公众号 QbitAI 智能手机以iPhone和安卓来划分阵营. 而智能手表及可穿戴,顶流玩家最具代表性的就是Apple Watch和华米. 但问题也来了-- ...

  7. 第1章 当我们谈论算法的时候,我们在谈论什么?

    无论是BAT,还是FLAG,但凡有点儿水平的技术公司,面试都要面算法.为什么算法这么重要?在工作中,真的会使用算法吗?学了算法到底有什么用?当我们谈论算法的时候,我们在谈论什么? <大话数据结构 ...

  8. LED灯条亮度色温调节

    一般LED灯条为12V或者24V供电,恒压驱动,由于LED灯条中已经内嵌了限流电阻,因此不需要使用复杂的恒流措施.对LED灯条进行色温和亮度的调节,可以通过PWM来开关MOS管. 正白4000~450 ...

  9. 怎样把 Boot Camp 里 Windows 的色温调节得和 Mac OS X 一致

    这个原因很简单,因为Windows 7默认无任何符合这台使用机器色彩管理的介入,它是统一默认归于一个共性sRGB,并不真正调用当前所用显示器的色彩配置文件.它不是简单说色温太高,它就是偏色的,完全不靠 ...

最新文章

  1. 关于Unity中的光照(六)
  2. 【若依(ruoyi)】打开新的选项卡
  3. Windows 11 小技巧- WSL运行本地GPU算力
  4. array_combine()
  5. 高并发编程_高并发编程系列:全面剖析Java并发编程之AQS的核心实现
  6. 浅谈asio中async_accept函数占用内存高的写法
  7. bootstrapV4.6.0内间距、外间距(官方hack类css代码)-解读篇
  8. Codeforces 484E Sign on Fence(是持久的段树+二分法)
  9. 完全卸载VS 2015各版本
  10. 2016最新iOS开发证书配置和安装的详细步骤攻略
  11. iPhone/iPad解锁屏幕密码
  12. mysql 按每月自定天数统计数据
  13. 网站建设多少钱(做一个网站需要多少钱)
  14. Varscan2 Call snp_indel
  15. 拼团小程序源码_微信小程序拼团系统为什么很多商家开发
  16. 第02章 c语言初探(c语言笔记)2.1 第一个 C 语言程序
  17. 用 Adobe 设置 PDF 文件在文件管理器右侧预览窗格预览
  18. 【计算机网络】因特网概述
  19. Nowcoder. 链表的回文结构
  20. API ShowWindow

热门文章

  1. 马尔科夫随机场简单理解
  2. MATLAB如何绘制每组数量不一致柱状图
  3. PATH,PYTHONPATH 与sys.path的区别
  4. ARM学习系列 ---- RISC和CISC概述
  5. RSPSS重复测量方差分析
  6. 微信小程序如何转云开发
  7. indesign页眉如何左右分布_InDesign排版技巧
  8. 漫画 | 悲催的中国式软件开发
  9. ICPC 2022西安回顾
  10. 7-42 打印倒直角三角形图案 (15 分)