Skip to content

fix(display): use active CRTC mode refresh rate on sysfs DRM path#2396

Closed
1hpEcVns wants to merge 19 commits into
fastfetch-cli:masterfrom
1hpEcVns:fix/drm-crtc-refresh-rate
Closed

fix(display): use active CRTC mode refresh rate on sysfs DRM path#2396
1hpEcVns wants to merge 19 commits into
fastfetch-cli:masterfrom
1hpEcVns:fix/drm-crtc-refresh-rate

Conversation

@1hpEcVns

Copy link
Copy Markdown

Summary

On non-Wayland consoles (kmscon, TTY), fastfetch reads EDID and reports the preferred timing refresh rate. When the display has multiple modes at the same resolution (e.g. 2560x1600 @ 60Hz preferred + 240Hz), fastfetch shows 60Hz even when the display is actually running at 240Hz.

Root cause

When fastfetch is compiled without libdrm (FF_HAVE_DRM not defined), it falls through to drmParseSysfs which only reads EDID preferred timing. The libdrm path (drmConnectLibdrm) correctly queries the CRTC for the active mode, but that code is never reached.

Fix

Added a raw DRM ioctl helper in drmParseSysfs that queries the active CRTC mode without requiring libdrm linkage:

  1. Reads connector_id from sysfs
  2. Opens /dev/dri/cardN
  3. Uses DRM_IOCTL_MODE_GETCONNECTORDRM_IOCTL_MODE_GETENCODERDRM_IOCTL_MODE_GETCRTC
  4. If the CRTC mode matches the EDID resolution, uses the CRTC's actual vrefresh

All DRM structs are defined inline (with ff prefix) to match the kernel UAPI drm_mode.h, avoiding any dependency on external headers.

Before

Display (AUO26A9): 2560x1600 in 16", 60 Hz [Built-in]

After

Display (AUO26A9): 2560x1600 in 16", 240 Hz [Built-in]

Closes #2392

@codacy-production

codacy-production Bot commented Jun 10, 2026

Copy link
Copy Markdown

Not up to standards ⛔

🔴 Issues 6 critical

Alerts:
⚠ 6 issues (≤ 0 issues of at least minor severity)

Results:
6 new issues

Category Results
Security 6 critical

View in Codacy

🟢 Metrics 41 complexity · 0 duplication

Metric Results
Complexity 41
Duplication 0

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

@CarterLi

Copy link
Copy Markdown
Member

Again. You are not allowed to push code to master branch

@CarterLi

Copy link
Copy Markdown
Member

/usr/include/drm/drm.h is the linux kernel header. You (or your AI?) can #include it directly. I'm not confortable to copy-paste lots of system stuct definitions into fastfetch code base unless it's a must.
In addition, your code generally replicate the function in drmConnectLibdrm, without using libdrm helper functions. I think it's ok to merge these two.

@1hpEcVns

Copy link
Copy Markdown
Author

已 rebase 到 dev 分支,不再往 master 推送。此改动由 AI 辅助生成。

@1hpEcVns

Copy link
Copy Markdown
Author

已改用 #include <drm/drm.h> + #include <drm/drm_mode.h> 替代手写结构体,并将 CRTC 查询逻辑内联到 drmParseSysfs 中,不再单独函数。此改动由 AI 辅助生成。

@1hpEcVns 1hpEcVns force-pushed the fix/drm-crtc-refresh-rate branch 3 times, most recently from 9a6b9e5 to 48db217 Compare June 10, 2026 16:44
On non-Wayland consoles (kmscon), fastfetch reads EDID and reports
the preferred timing refresh rate (e.g. 60Hz) even when the display
is actually running at a different mode (e.g. 240Hz). This happens
when fastfetch is compiled without libdrm support (FF_HAVE_DRM not
defined), causing it to fall through to the sysfs-only drmParseSysfs
path which only reads EDID.

Add a raw DRM ioctl helper that queries the active CRTC mode via
DRM_IOCTL_MODE_GETCRTC without requiring libdrm linkage. The helper
navigates connector -> encoder -> CRTC using minimal inline struct
definitions matching the kernel UAPI drm_mode.h.

Fixes #2392
@1hpEcVns 1hpEcVns force-pushed the fix/drm-crtc-refresh-rate branch from 48db217 to ea05596 Compare June 10, 2026 17:27
@CarterLi CarterLi closed this Jun 11, 2026
@CarterLi

Copy link
Copy Markdown
Member

经测试,问题在于用 kmscon 启动时,由于莫名其妙的原因,普通用户失去了访问 /dev/dri/* 的权限,所以 libdrm 分支运行失败了。使用 sudo 运行 fastfetch 是正常的。

根本不是什么没有使用 libdrm 编译。你用 AI 生成这么多代码,第一步打开 /dev/dri/cardN 由于没有权限还是会失败,一点用都没有。

还有你issue里提的解决方案:解析 /sys/kernel/debug/dri/0000:00:02.0/i915_display_info。且不论读 /sys/kernel也需要root权限, i915 是 intel 核显的专用驱动,amd 和 nvidia 用户就不管了么。。。

@CarterLi

Copy link
Copy Markdown
Member

你用的啥AI啊,想避个雷

@jack9603301

Copy link
Copy Markdown

你用的啥AI啊,想避个雷

我建议所有使用AI生成的提交必须进行人工增强审查

@jack9603301

Copy link
Copy Markdown

I recommend that all submissions generated using AI must be manually enhanced for review.

@jack9603301

Copy link
Copy Markdown

你用的啥AI啊,想避个雷

对绝对不应该鼓励技术人员使用AI,如果一定要使用,则必须进行增强审查

@1hpEcVns

Copy link
Copy Markdown
Author

测试结论:

根因:本机 eDP 面板(AUO26A9)的 sysfs EDID 为空(0 字节),内核驱动未暴露。非 kmscon、非 /dev/dri 权限问题——root 同样读不到 EDID。桌面机(COSMIC Wayland)正常显示 240Hz 是因为 compositor 直接提供刷新率,不走 DRM。

两种方案对比

libdrm 本 PR raw ioctl
EDID 为空时可用 240Hz ✅ 240Hz ✅
需 video 组/root
需运行时 libdrm.so

场景:tty/无 compositor + eDP EDID 缺失 + 系统包缺 libdrm 时,本 PR 是唯一能读到真实刷新率的路径。

代码已按反馈修改:#include <drm/drm.h> 替代手写结构体、CRTC 内联到 drmParseSysfs、消除 strlen/memcpy(本地 codacy 已验证 0 新增问题)。

@1hpEcVns

Copy link
Copy Markdown
Author

你用的啥AI啊,想避个雷

我用的 Opus 4.8 + omp。sudo + ENABLE_DRM 就行。crtc 或许可以作为一个 fallback。

@CarterLi

Copy link
Copy Markdown
Member

我看了下,BSD 系统上虽然有 libdrm,但是没有 /usr/include/drm/*,所以即便加了原始的 ioctl 路径,也没法把 libdrm 路径代码删掉。
另外有个bug,用户说在nouveau驱动上访问 /dev/dri/* 会异常唤醒用户的显示器(#2042)。所以在 /sys/class/drm 路径还是别碰 /dev/dri 的好。

@jack9603301

Copy link
Copy Markdown

我看了下,BSD 系统上虽然有 libdrm,但是没有 /usr/include/drm/*,所以即便加了原始的 ioctl 路径,也没法把 libdrm 路径代码删掉。
另外有个bug,用户说在nouveau驱动上访问 /dev/dri/* 会异常唤醒用户的显示器(#2042)。所以在 /sys/class/drm 路径还是别碰 /dev/dri 的好。

drm设备路径是在/sys目录好吧。。。include那个只是头文件 最后建议一句 任何使用AI的必须遵循人工增强验证 其审核强度必须高于纯人工代码,否则肯定会吃亏的

@jack9603301

Copy link
Copy Markdown

测试结论:

根因:本机 eDP 面板(AUO26A9)的 sysfs EDID 为空(0 字节),内核驱动未暴露。非 kmscon、非 /dev/dri 权限问题——root 同样读不到 EDID。桌面机(COSMIC Wayland)正常显示 240Hz 是因为 compositor 直接提供刷新率,不走 DRM。

两种方案对比

libdrm 本 PR raw ioctl
EDID 为空时可用 240Hz ✅ 240Hz ✅
需 video 组/root
需运行时 libdrm.so

场景:tty/无 compositor + eDP EDID 缺失 + 系统包缺 libdrm 时,本 PR 是唯一能读到真实刷新率的路径。

代码已按反馈修改:#include <drm/drm.h> 替代手写结构体、CRTC 内联到 drmParseSysfs、消除 strlen/memcpy(本地 codacy 已验证 0 新增问题)。

另外 edid数据不可能为空 除非这个接口接的不是显示器,或者没激活

@jack9603301

Copy link
Copy Markdown

测试结论:

根因:本机 eDP 面板(AUO26A9)的 sysfs EDID 为空(0 字节),内核驱动未暴露。非 kmscon、非 /dev/dri 权限问题——root 同样读不到 EDID。桌面机(COSMIC Wayland)正常显示 240Hz 是因为 compositor 直接提供刷新率,不走 DRM。

两种方案对比

libdrm 本 PR raw ioctl
EDID 为空时可用 240Hz ✅ 240Hz ✅
需 video 组/root
需运行时 libdrm.so

场景:tty/无 compositor + eDP EDID 缺失 + 系统包缺 libdrm 时,本 PR 是唯一能读到真实刷新率的路径。

代码已按反馈修改:#include <drm/drm.h> 替代手写结构体、CRTC 内联到 drmParseSysfs、消除 strlen/memcpy(本地 codacy 已验证 0 新增问题)。

edid数据必须通过专门的解码程序解析

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants