|
5 | 5 |
|
6 | 6 | #ifdef __linux__ |
7 | 7 | #include <dirent.h> |
| 8 | + #include <sys/ioctl.h> |
| 9 | + #include <fcntl.h> |
| 10 | + #include <stdlib.h> |
| 11 | + |
| 12 | + |
| 13 | + #if __has_include(<drm/drm.h>) && __has_include(<drm/drm_mode.h>) |
| 14 | + #include <drm/drm.h> |
| 15 | + #include <drm/drm_mode.h> |
| 16 | + #define FF_HAVE_DRM_UAPI |
| 17 | + #endif |
| 18 | + |
8 | 19 |
|
9 | 20 | static const char* drmParseSysfs(FFDisplayServerResult* result) { |
10 | 21 | const char* drmDirPath = "/sys/class/drm/"; |
@@ -76,6 +87,55 @@ static const char* drmParseSysfs(FFDisplayServerResult* result) { |
76 | 87 | ffEdidGetPhysicalSize(edidData, &physicalWidth, &physicalHeight); |
77 | 88 | } |
78 | 89 |
|
| 90 | + // Try to get the actual active refresh rate from the CRTC. |
| 91 | + // EDID preferred timing (e.g. 60Hz) can differ from the active mode (e.g. 240Hz) |
| 92 | + // when the display is set to a non-preferred mode with the same resolution. |
| 93 | + if (width > 0 && height > 0) { |
| 94 | + // Extract card number from entry name like "card1-eDP-1" |
| 95 | + const char* entryName = entry->d_name; |
| 96 | + if (ffStrStartsWith(entryName, "card")) { |
| 97 | + entryName += sizeof("card") - 1; |
| 98 | + // Parse card number directly from d_name |
| 99 | + int cardNum = 0; |
| 100 | + for (const char* p = entryName; *p >= '0' && *p <= '9'; p++) |
| 101 | + cardNum = cardNum * 10 + (*p - '0'); |
| 102 | + |
| 103 | + if (cardNum >= 0) { |
| 104 | + FF_STRBUF_AUTO_DESTROY cardPath = ffStrbufCreateF("/dev/dri/card%d", cardNum); |
| 105 | + |
| 106 | + // Read connector_id from sysfs |
| 107 | + FF_STRBUF_AUTO_DESTROY connIdPath = ffStrbufCreateA(64); |
| 108 | + ffStrbufAppendS(&connIdPath, drmDirPath); |
| 109 | + ffStrbufAppendS(&connIdPath, entry->d_name); |
| 110 | + ffStrbufAppendS(&connIdPath, "/connector_id"); |
| 111 | + char connIdBuf[16] = {}; |
| 112 | + if (ffReadFileData(connIdPath.chars, ARRAY_SIZE(connIdBuf), connIdBuf) > 0) { |
| 113 | + uint32_t connId = (uint32_t)strtoul(connIdBuf, NULL, 10); |
| 114 | + if (connId > 0) { |
| 115 | +#ifdef FF_HAVE_DRM_UAPI |
| 116 | + int fd = open(cardPath.chars, O_RDONLY | O_CLOEXEC); |
| 117 | + if (fd >= 0) { |
| 118 | + // Query active CRTC mode via raw DRM ioctls |
| 119 | + struct drm_mode_get_connector conn = { .connector_id = connId }; |
| 120 | + if (ioctl(fd, DRM_IOCTL_MODE_GETCONNECTOR, &conn) >= 0 && conn.encoder_id) { |
| 121 | + struct drm_mode_get_encoder enc = { .encoder_id = conn.encoder_id }; |
| 122 | + if (ioctl(fd, DRM_IOCTL_MODE_GETENCODER, &enc) >= 0 && enc.crtc_id) { |
| 123 | + struct drm_mode_crtc crtc = { .crtc_id = enc.crtc_id }; |
| 124 | + if (ioctl(fd, DRM_IOCTL_MODE_GETCRTC, &crtc) >= 0) { |
| 125 | + if (crtc.mode_valid && crtc.mode.hdisplay == (uint16_t)width && crtc.mode.vdisplay == (uint16_t)height) |
| 126 | + refreshRate = (double)crtc.mode.vrefresh; |
| 127 | + } |
| 128 | + } |
| 129 | + } |
| 130 | + close(fd); |
| 131 | + } |
| 132 | +#endif |
| 133 | + } |
| 134 | + } |
| 135 | + } |
| 136 | + } |
| 137 | + } |
| 138 | + |
79 | 139 | FFDisplayResult* item = ffdsAppendDisplay( |
80 | 140 | result, |
81 | 141 | width, |
|
0 commit comments