From 5a7520d2529204c5b9eaeaf17675a7fe1d7c1852 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Tapani=20P=C3=A4lli?= Date: Sun, 7 May 2023 21:28:54 +0300 Subject: [PATCH] egl/loader: move crtc resource infrastructure as common helper MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Patch moves (and renames) the infrastructure to fix compilation failures when dri3 is not enabled in the build. Fixes: 3170b63314f ("loader: Add infrastructure for tracking active CRTC resources"); Closes: https://gitlab.freedesktop.org/mesa/mesa/-/issues/8476 Signed-off-by: Tapani Pälli Reviewed-by: Kenneth Graunke Part-of: --- src/egl/drivers/dri2/egl_dri2.h | 3 +- src/egl/drivers/dri2/platform_x11.c | 10 +- src/loader/loader_dri3_helper.c | 176 ----------------------------------- src/loader/loader_dri3_helper.h | 35 ------- src/loader/loader_dri_helper.c | 178 ++++++++++++++++++++++++++++++++++++ src/loader/loader_dri_helper.h | 48 ++++++++++ src/loader/meson.build | 4 +- 7 files changed, 235 insertions(+), 219 deletions(-) diff --git a/src/egl/drivers/dri2/egl_dri2.h b/src/egl/drivers/dri2/egl_dri2.h index 0fab2aa..7693fed 100644 --- a/src/egl/drivers/dri2/egl_dri2.h +++ b/src/egl/drivers/dri2/egl_dri2.h @@ -38,6 +38,7 @@ #include #include +#include "loader_dri_helper.h" #ifdef HAVE_DRI3 #include "loader_dri3_helper.h" #endif @@ -287,7 +288,7 @@ struct dri2_egl_display int present_major_version; int present_minor_version; struct loader_dri3_extensions loader_dri3_ext; - struct loader_dri3_screen_resources screen_resources; + struct loader_screen_resources screen_resources; #endif #endif diff --git a/src/egl/drivers/dri2/platform_x11.c b/src/egl/drivers/dri2/platform_x11.c index 0a4889c..917c82b 100644 --- a/src/egl/drivers/dri2/platform_x11.c +++ b/src/egl/drivers/dri2/platform_x11.c @@ -1226,7 +1226,7 @@ dri2_x11_get_msc_rate(_EGLDisplay *display, _EGLSurface *surface, { struct dri2_egl_display *dri2_dpy = dri2_egl_display(display); - loader_dri3_update_screen_resources(&dri2_dpy->screen_resources); + loader_update_screen_resources(&dri2_dpy->screen_resources); if (dri2_dpy->screen_resources.num_crtcs == 0) { /* If there's no CRTC active, use the present fake vblank of 1Hz */ @@ -1267,7 +1267,7 @@ dri2_x11_get_msc_rate(_EGLDisplay *display, _EGLSurface *surface, int area = 0; for (unsigned c = 0; c < dri2_dpy->screen_resources.num_crtcs; c++) { - struct loader_dri3_crtc_info *crtc = + struct loader_crtc_info *crtc = &dri2_dpy->screen_resources.crtcs[c]; int c_area = box_intersection_area(reply->dst_x, reply->dst_y, @@ -1663,8 +1663,8 @@ dri2_initialize_x11_dri3(_EGLDisplay *disp) if (!dri2_x11_add_configs_for_visuals(dri2_dpy, disp, false)) goto cleanup; - loader_dri3_init_screen_resources(&dri2_dpy->screen_resources, - dri2_dpy->conn, dri2_dpy->screen); + loader_init_screen_resources(&dri2_dpy->screen_resources, + dri2_dpy->conn, dri2_dpy->screen); dri2_dpy->loader_dri3_ext.core = dri2_dpy->core; dri2_dpy->loader_dri3_ext.image_driver = dri2_dpy->image_driver; @@ -1815,7 +1815,7 @@ void dri2_teardown_x11(struct dri2_egl_display *dri2_dpy) { if (dri2_dpy->dri2_major >= 3) - loader_dri3_destroy_screen_resources(&dri2_dpy->screen_resources); + loader_destroy_screen_resources(&dri2_dpy->screen_resources); if (dri2_dpy->own_device) xcb_disconnect(dri2_dpy->conn); diff --git a/src/loader/loader_dri3_helper.c b/src/loader/loader_dri3_helper.c index 63be04ed..0d9f108 100644 --- a/src/loader/loader_dri3_helper.c +++ b/src/loader/loader_dri3_helper.c @@ -2329,182 +2329,6 @@ loader_dri3_update_drawable_geometry(struct loader_dri3_drawable *draw) } } -void -loader_dri3_init_screen_resources(struct loader_dri3_screen_resources *res, - xcb_connection_t *conn, - xcb_screen_t *screen) -{ - res->conn = conn; - res->screen = screen; - res->crtcs = NULL; - - mtx_init(&res->mtx, mtx_plain); -} - -void -loader_dri3_destroy_screen_resources(struct loader_dri3_screen_resources *res) -{ - mtx_destroy(&res->mtx); -} - -static unsigned -gcd_u32(unsigned a, unsigned b) -{ - assert(a > 0 || b > 0); - - while (b != 0) { - unsigned remainder = a % b; - a = b; - b = remainder; - } - - return a; -} - -static void -calculate_refresh_rate(const xcb_randr_mode_info_t *mode, - unsigned *numerator, unsigned *denominator) -{ - unsigned vtotal = mode->vtotal; - - /* Double-scan doubles the number of lines */ - if (mode->mode_flags & XCB_RANDR_MODE_FLAG_DOUBLE_SCAN) - vtotal *= 2; - - /* Interlace splits the frame into two fields; typically the monitor - * reports field rate. - */ - if (mode->mode_flags & XCB_RANDR_MODE_FLAG_INTERLACE) - vtotal /= 2; - - uint32_t dots = mode->htotal * vtotal; - - if (dots == 0) { - *numerator = 0; - *denominator = 1; - } else { - uint32_t gcd = gcd_u32(mode->dot_clock, dots); - - *numerator = mode->dot_clock / gcd; - *denominator = dots / gcd; - } -} - -bool -loader_dri3_update_screen_resources(struct loader_dri3_screen_resources *res) -{ - xcb_randr_get_crtc_info_cookie_t *crtc_cookies; - - /* If we have cached screen resources information, check each CRTC to - * see if it's up to date. Ideally, we'd watch PresentConfigureNotify - * events on the root window to see if something changed, but those only - * fire if the geometry changes. It misses CRTC changes which only - * alter the refresh rate. We also can't watch RandR events internally - * because they aren't XGE events. So, we just check every CRTC for now. - */ - bool config_unchanged = res->crtcs != NULL; - - crtc_cookies = malloc(res->num_crtcs * sizeof(*crtc_cookies)); - - for (unsigned c = 0; c < res->num_crtcs; c++) { - crtc_cookies[c] = - xcb_randr_get_crtc_info_unchecked(res->conn, res->crtcs[c].id, - res->config_timestamp); - } - - for (unsigned c = 0; c < res->num_crtcs; c++) { - xcb_randr_get_crtc_info_reply_t *reply = - xcb_randr_get_crtc_info_reply(res->conn, crtc_cookies[c], NULL); - - /* Although randrproto 1.4.0 says that RRGetCrtcInfo is supposed to - * return InvalidConfigTime if config_timestamp is out of date, the - * implementation in xserver as of 21.x doesn't actually do so. To - * detect changes in refresh rate, we check the returned timestamp - * on each tracked CRTC. - */ - if (!reply || - reply->status == XCB_RANDR_SET_CONFIG_INVALID_CONFIG_TIME || - reply->timestamp != res->crtcs[c].timestamp) { - config_unchanged = false; - /* continue to consume all replies */ - } - - free(reply); - } - - free(crtc_cookies); - - if (config_unchanged) - return false; - - /* Do RRGetScreenResourcesCurrent to query the list of CRTCs and modes, - * then RRGetCrtcInfo on each CRTC to determine what mode each uses, and - * use the mode to calculate the refresh rate. - */ - mtx_lock(&res->mtx); - - xcb_randr_get_screen_resources_current_cookie_t cookie = - xcb_randr_get_screen_resources_current_unchecked(res->conn, - res->screen->root); - xcb_randr_get_screen_resources_current_reply_t *reply = - xcb_randr_get_screen_resources_current_reply(res->conn, cookie, NULL); - - xcb_randr_crtc_t *new_crtcs = - xcb_randr_get_screen_resources_current_crtcs(reply); - - xcb_randr_mode_info_t *new_modes = - xcb_randr_get_screen_resources_current_modes(reply); - - res->config_timestamp = reply->config_timestamp; - - free(res->crtcs); - res->crtcs = calloc(reply->num_crtcs, sizeof(*res->crtcs)); - - crtc_cookies = malloc(reply->num_crtcs * sizeof(*crtc_cookies)); - - for (unsigned c = 0; c < reply->num_crtcs; c++) { - crtc_cookies[c] = - xcb_randr_get_crtc_info_unchecked(res->conn, new_crtcs[c], - res->config_timestamp); - } - - unsigned i = 0; - for (unsigned c = 0; c < reply->num_crtcs; c++) { - xcb_randr_get_crtc_info_reply_t *crtc_info = - xcb_randr_get_crtc_info_reply(res->conn, crtc_cookies[c], NULL); - - if (!crtc_info || crtc_info->mode == XCB_NONE) - continue; - - res->crtcs[i].id = new_crtcs[c]; - res->crtcs[i].timestamp = crtc_info->timestamp; - res->crtcs[i].x = crtc_info->x; - res->crtcs[i].y = crtc_info->y; - res->crtcs[i].width = crtc_info->width; - res->crtcs[i].height = crtc_info->height; - - for (int m = 0; m < reply->num_modes; m++) { - if (new_modes[m].id == crtc_info->mode) { - calculate_refresh_rate(&new_modes[m], - &res->crtcs[i].refresh_numerator, - &res->crtcs[i].refresh_denominator); - break; - } - } - - i++; - free(crtc_info); - } - - res->num_crtcs = i; - - free(crtc_cookies); - free(reply); - - mtx_unlock(&res->mtx); - return true; -} - /** * Make sure the server has flushed all pending swap buffers to hardware * for this drawable. Ideally we'd want to send an X protocol request to diff --git a/src/loader/loader_dri3_helper.h b/src/loader/loader_dri3_helper.h index eb7f325..1fd340b 100644 --- a/src/loader/loader_dri3_helper.h +++ b/src/loader/loader_dri3_helper.h @@ -298,39 +298,4 @@ loader_dri3_swapbuffer_barrier(struct loader_dri3_drawable *draw); void loader_dri3_close_screen(__DRIscreen *dri_screen); -struct loader_dri3_crtc_info { - xcb_randr_crtc_t id; - xcb_timestamp_t timestamp; - - int16_t x, y; - uint16_t width, height; - - unsigned refresh_numerator; - unsigned refresh_denominator; -}; - -struct loader_dri3_screen_resources { - mtx_t mtx; - - xcb_connection_t *conn; - xcb_screen_t *screen; - - xcb_timestamp_t config_timestamp; - - /* Number of CRTCs with an active mode set */ - unsigned num_crtcs; - struct loader_dri3_crtc_info *crtcs; -}; - -void -loader_dri3_init_screen_resources(struct loader_dri3_screen_resources *res, - xcb_connection_t *conn, - xcb_screen_t *screen); -bool -loader_dri3_update_screen_resources(struct loader_dri3_screen_resources *res); - -void -loader_dri3_destroy_screen_resources(struct loader_dri3_screen_resources *res); - - #endif diff --git a/src/loader/loader_dri_helper.c b/src/loader/loader_dri_helper.c index 89d41bd..f1afce4 100644 --- a/src/loader/loader_dri_helper.c +++ b/src/loader/loader_dri_helper.c @@ -151,3 +151,181 @@ loader_image_format_to_fourcc(int format) } return 0; } + +#ifdef HAVE_X11_PLATFORM +void +loader_init_screen_resources(struct loader_screen_resources *res, + xcb_connection_t *conn, + xcb_screen_t *screen) +{ + res->conn = conn; + res->screen = screen; + res->crtcs = NULL; + + mtx_init(&res->mtx, mtx_plain); +} + +void +loader_destroy_screen_resources(struct loader_screen_resources *res) +{ + mtx_destroy(&res->mtx); +} + +static unsigned +gcd_u32(unsigned a, unsigned b) +{ + assert(a > 0 || b > 0); + + while (b != 0) { + unsigned remainder = a % b; + a = b; + b = remainder; + } + + return a; +} + +static void +calculate_refresh_rate(const xcb_randr_mode_info_t *mode, + unsigned *numerator, unsigned *denominator) +{ + unsigned vtotal = mode->vtotal; + + /* Double-scan doubles the number of lines */ + if (mode->mode_flags & XCB_RANDR_MODE_FLAG_DOUBLE_SCAN) + vtotal *= 2; + + /* Interlace splits the frame into two fields; typically the monitor + * reports field rate. + */ + if (mode->mode_flags & XCB_RANDR_MODE_FLAG_INTERLACE) + vtotal /= 2; + + uint32_t dots = mode->htotal * vtotal; + + if (dots == 0) { + *numerator = 0; + *denominator = 1; + } else { + uint32_t gcd = gcd_u32(mode->dot_clock, dots); + + *numerator = mode->dot_clock / gcd; + *denominator = dots / gcd; + } +} + +bool +loader_update_screen_resources(struct loader_screen_resources *res) +{ + xcb_randr_get_crtc_info_cookie_t *crtc_cookies; + + /* If we have cached screen resources information, check each CRTC to + * see if it's up to date. Ideally, we'd watch PresentConfigureNotify + * events on the root window to see if something changed, but those only + * fire if the geometry changes. It misses CRTC changes which only + * alter the refresh rate. We also can't watch RandR events internally + * because they aren't XGE events. So, we just check every CRTC for now. + */ + bool config_unchanged = res->crtcs != NULL; + + crtc_cookies = malloc(res->num_crtcs * sizeof(*crtc_cookies)); + + for (unsigned c = 0; c < res->num_crtcs; c++) { + crtc_cookies[c] = + xcb_randr_get_crtc_info_unchecked(res->conn, res->crtcs[c].id, + res->config_timestamp); + } + + for (unsigned c = 0; c < res->num_crtcs; c++) { + xcb_randr_get_crtc_info_reply_t *reply = + xcb_randr_get_crtc_info_reply(res->conn, crtc_cookies[c], NULL); + + /* Although randrproto 1.4.0 says that RRGetCrtcInfo is supposed to + * return InvalidConfigTime if config_timestamp is out of date, the + * implementation in xserver as of 21.x doesn't actually do so. To + * detect changes in refresh rate, we check the returned timestamp + * on each tracked CRTC. + */ + if (!reply || + reply->status == XCB_RANDR_SET_CONFIG_INVALID_CONFIG_TIME || + reply->timestamp != res->crtcs[c].timestamp) { + config_unchanged = false; + /* continue to consume all replies */ + } + + free(reply); + } + + free(crtc_cookies); + + if (config_unchanged) + return false; + + /* Do RRGetScreenResourcesCurrent to query the list of CRTCs and modes, + * then RRGetCrtcInfo on each CRTC to determine what mode each uses, and + * use the mode to calculate the refresh rate. + */ + mtx_lock(&res->mtx); + + xcb_randr_get_screen_resources_current_cookie_t cookie = + xcb_randr_get_screen_resources_current_unchecked(res->conn, + res->screen->root); + xcb_randr_get_screen_resources_current_reply_t *reply = + xcb_randr_get_screen_resources_current_reply(res->conn, cookie, NULL); + + xcb_randr_crtc_t *new_crtcs = + xcb_randr_get_screen_resources_current_crtcs(reply); + + xcb_randr_mode_info_t *new_modes = + xcb_randr_get_screen_resources_current_modes(reply); + + res->config_timestamp = reply->config_timestamp; + + free(res->crtcs); + res->crtcs = calloc(reply->num_crtcs, sizeof(*res->crtcs)); + + crtc_cookies = malloc(reply->num_crtcs * sizeof(*crtc_cookies)); + + for (unsigned c = 0; c < reply->num_crtcs; c++) { + crtc_cookies[c] = + xcb_randr_get_crtc_info_unchecked(res->conn, new_crtcs[c], + res->config_timestamp); + } + + unsigned i = 0; + for (unsigned c = 0; c < reply->num_crtcs; c++) { + xcb_randr_get_crtc_info_reply_t *crtc_info = + xcb_randr_get_crtc_info_reply(res->conn, crtc_cookies[c], NULL); + + if (!crtc_info || crtc_info->mode == XCB_NONE) + continue; + + res->crtcs[i].id = new_crtcs[c]; + res->crtcs[i].timestamp = crtc_info->timestamp; + res->crtcs[i].x = crtc_info->x; + res->crtcs[i].y = crtc_info->y; + res->crtcs[i].width = crtc_info->width; + res->crtcs[i].height = crtc_info->height; + + for (int m = 0; m < reply->num_modes; m++) { + if (new_modes[m].id == crtc_info->mode) { + calculate_refresh_rate(&new_modes[m], + &res->crtcs[i].refresh_numerator, + &res->crtcs[i].refresh_denominator); + break; + } + } + + i++; + free(crtc_info); + } + + res->num_crtcs = i; + + free(crtc_cookies); + free(reply); + + mtx_unlock(&res->mtx); + return true; +} +#endif diff --git a/src/loader/loader_dri_helper.h b/src/loader/loader_dri_helper.h index ba34980..20ac24e 100644 --- a/src/loader/loader_dri_helper.h +++ b/src/loader/loader_dri_helper.h @@ -18,11 +18,45 @@ * OF THIS SOFTWARE. */ +#ifndef LOADER_DRI_HELPER_H +#define LOADER_DRI_HELPER_H + #include #include #include /* dri_interface needs GL types */ #include +#include + +#ifdef HAVE_X11_PLATFORM +#include +#include +#include + +struct loader_crtc_info { + xcb_randr_crtc_t id; + xcb_timestamp_t timestamp; + + int16_t x, y; + uint16_t width, height; + + unsigned refresh_numerator; + unsigned refresh_denominator; +}; + +struct loader_screen_resources { + mtx_t mtx; + + xcb_connection_t *conn; + xcb_screen_t *screen; + + xcb_timestamp_t config_timestamp; + + /* Number of CRTCs with an active mode set */ + unsigned num_crtcs; + struct loader_crtc_info *crtcs; +}; +#endif __DRIimage *loader_dri_create_image(__DRIscreen *screen, const __DRIimageExtension *image, @@ -40,3 +74,17 @@ bool dri_valid_swap_interval(__DRIscreen *driScreen, int loader_image_format_to_fourcc(int format); + +#ifdef HAVE_X11_PLATFORM +void +loader_init_screen_resources(struct loader_screen_resources *res, + xcb_connection_t *conn, + xcb_screen_t *screen); +bool +loader_update_screen_resources(struct loader_screen_resources *res); + +void +loader_destroy_screen_resources(struct loader_screen_resources *res); +#endif + +#endif /* LOADER_DRI_HELPER_H */ diff --git a/src/loader/meson.build b/src/loader/meson.build index b03b229..81779a3 100644 --- a/src/loader/meson.build +++ b/src/loader/meson.build @@ -28,7 +28,7 @@ if with_platform_x11 and with_dri3 include_directories : [inc_include, inc_src], dependencies : [ dep_libdrm, dep_xcb_dri3, dep_xcb_present, dep_xcb_sync, dep_xshmfence, - dep_xcb_xfixes, dep_xcb_xrandr, + dep_xcb_xfixes, ], build_by_default : false, ) @@ -46,6 +46,6 @@ libloader = static_library( c_args : loader_c_args, gnu_symbol_visibility : 'hidden', include_directories : [inc_include, inc_src, inc_util], - dependencies : [dep_libdrm, dep_thread], + dependencies : [dep_libdrm, dep_thread, dep_xcb_xrandr], build_by_default : false, ) -- 2.7.4