diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2015-04-01 12:39:48 +0100 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2015-04-01 12:55:44 +0100 |
commit | 2f047c62783a187067921e1aaf5572fb8647bd84 (patch) | |
tree | 3ffa8f2a9f186bcb6bf4e20735f86d99d515dd0b /tools/dri3info.c | |
parent | 745c21fb1aa1fcd54e9a9aeaa7fe6877af39f2f1 (diff) |
tools/dri3info: Query refresh rate on Primary monitor
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Diffstat (limited to 'tools/dri3info.c')
-rw-r--r-- | tools/dri3info.c | 211 |
1 files changed, 200 insertions, 11 deletions
diff --git a/tools/dri3info.c b/tools/dri3info.c index 65874111..2c2ef95f 100644 --- a/tools/dri3info.c +++ b/tools/dri3info.c @@ -29,17 +29,63 @@ #include <unistd.h> #include <stdio.h> #include <stdlib.h> +#include <stdint.h> #include <string.h> #include <sys/stat.h> #include <drm.h> #include <xf86drm.h> +#include <X11/extensions/Xrandr.h> +#include <X11/extensions/xf86vmode.h> + +static int dri3_query_version(Display *dpy, int *major, int *minor) +{ + xcb_connection_t *c = XGetXCBConnection(dpy); + xcb_dri3_query_version_reply_t *reply; + xcb_generic_error_t *error; + + *major = *minor = -1; + + reply = xcb_dri3_query_version_reply(c, + xcb_dri3_query_version(c, + XCB_DRI3_MAJOR_VERSION, + XCB_DRI3_MINOR_VERSION), + &error); + free(error); + if (reply == NULL) + return -1; + + *major = reply->major_version; + *minor = reply->minor_version; + free(reply); + + return 0; +} + +static int dri3_exists(Display *dpy) +{ + const xcb_query_extension_reply_t *ext; + int major, minor; + + ext = xcb_get_extension_data(XGetXCBConnection(dpy), &xcb_dri3_id); + if (ext == NULL || !ext->present) + return 0; + + if (dri3_query_version(dpy, &major, &minor) < 0) + return 0; + + return major >= 0; +} + static int dri3_open(Display *dpy) { xcb_connection_t *c = XGetXCBConnection(dpy); xcb_dri3_open_cookie_t cookie; xcb_dri3_open_reply_t *reply; + if (!dri3_exists(dpy)) + return -1; + cookie = xcb_dri3_open(c, RootWindow(dpy, DefaultScreen(dpy)), None); reply = xcb_dri3_open_reply(c, cookie, NULL); @@ -94,12 +140,149 @@ static void get_driver_name(int fd, char *name, int len) (void)drmIoctl(fd, DRM_IOCTL_VERSION, &version); } +static int compute_refresh_rate_from_mode(long n, long d, unsigned flags, + int32_t *numerator, + int32_t *denominator) +{ + int i; + + /* The mode flags are only defined privately to the Xserver (in xf86str.h) + * but they at least bit compatible between VidMode, RandR and DRM. + */ +# define V_INTERLACE 0x010 +# define V_DBLSCAN 0x020 + + if (flags & V_INTERLACE) + n *= 2; + else if (flags & V_DBLSCAN) + d *= 2; + + /* The OML_sync_control spec requires that if the refresh rate is a + * whole number, that the returned numerator be equal to the refresh + * rate and the denominator be 1. + */ + + if (n % d == 0) { + n /= d; + d = 1; + } + else { + static const unsigned f[] = { 13, 11, 7, 5, 3, 2, 0 }; + + /* This is a poor man's way to reduce a fraction. It's far from + * perfect, but it will work well enough for this situation. + */ + + for (i = 0; f[i] != 0; i++) { + while (n % f[i] == 0 && d % f[i] == 0) { + d /= f[i]; + n /= f[i]; + } + } + } + + *numerator = n; + *denominator = d; + return 1; +} + +static int RRGetMscRate(Display *dpy, int32_t *numerator, int32_t *denominator) +{ + int ret = 0; + Window root = RootWindow(dpy, DefaultScreen(dpy)); + XRRScreenResources *res; + int rr_event, rr_error; + RROutput primary; + RRMode mode = 0; + int n; + + if (!XRRQueryExtension(dpy, &rr_event, &rr_error)) + return ret; + + res = XRRGetScreenResourcesCurrent(dpy, root); + if (res == NULL) + return ret; + + /* Use the primary output if specified, otherwise + * use the mode on the first enabled crtc. + */ + primary = XRRGetOutputPrimary(dpy, root); + if (primary) { + XRROutputInfo *output; + + output = XRRGetOutputInfo(dpy, res, primary); + if (output != NULL) { + if (output->crtc) { + XRRCrtcInfo *crtc; + + crtc = XRRGetCrtcInfo(dpy, res, output->crtc); + if (crtc) { + mode = crtc->mode; + XRRFreeCrtcInfo(crtc); + } + } + XRRFreeOutputInfo(output); + } + } + + for (n = 0; mode == 0 && n < res->ncrtc; n++) { + XRRCrtcInfo *crtc; + + crtc = XRRGetCrtcInfo(dpy, res, res->crtcs[n]); + if (crtc) { + mode = crtc->mode; + XRRFreeCrtcInfo(crtc); + } + } + + for (n = 0; n < res->nmode; n++) { + if (res->modes[n].id == mode) { + ret = compute_refresh_rate_from_mode(res->modes[n].dotClock, + res->modes[n].hTotal*res->modes[n].vTotal, + res->modes[n].modeFlags, + numerator, denominator); + break; + } + } + + XRRFreeScreenResources(res); + return ret; +} + +static int VMGetMscRate(Display *dpy, int32_t *numerator, int32_t *denominator) +{ + XF86VidModeModeLine mode_line; + int dot_clock; + int i; + + if (XF86VidModeQueryVersion(dpy, &i, &i) && + XF86VidModeGetModeLine(dpy, DefaultScreen(dpy), &dot_clock, &mode_line)) + return compute_refresh_rate_from_mode(dot_clock * 1000, + mode_line.vtotal * mode_line.htotal, + mode_line.flags, + numerator, denominator); + + return 0; +} + +static int get_refresh_rate(Display *dpy, + int32_t *numerator, + int32_t *denominator) +{ + if (RRGetMscRate(dpy, numerator, denominator)) + return 1; + + if (VMGetMscRate(dpy, numerator, denominator)) + return 1; + + return 0; +} + static void info(const char *dpyname) { Display *dpy; int device; - char device_path[1024]; - char driver_name[1024]; + int32_t numerator, denominator; dpy = XOpenDisplay(dpyname); if (dpy == NULL) { @@ -108,21 +291,27 @@ static void info(const char *dpyname) return; } + printf("Display '%s'\n", DisplayString(dpy)); device = dri3_open(dpy); if (device < 0) { - printf("Unable to connect to DRI3 on display '%s'\n", - DisplayString(dpy)); - return; - } + printf("\tUnable to connect to DRI3\n"); + } else { + char device_path[1024]; + char driver_name[1024]; - get_device_path(device, device_path, sizeof(device_path)); - get_driver_name(device, driver_name, sizeof(driver_name)); + get_device_path(device, device_path, sizeof(device_path)); + get_driver_name(device, driver_name, sizeof(driver_name)); + + printf("Connected to DRI3, using fd %d which matches %s, driver %s\n", + device, device_path, driver_name); + close(device); + } - printf("Connected to DRI3 on display '%s', using fd %d: matches %s, driver %s\n", - DisplayString(dpy), device, device_path, driver_name); + if (get_refresh_rate(dpy, &numerator, &denominator)) + printf("\tPrimary refresh rate: %d/%d (%.1fHz)\n", + numerator, denominator, numerator/(float)denominator); XCloseDisplay(dpy); - close(device); } int main(int argc, char **argv) |