mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2025-12-23 11:10:10 +01:00
loader: Add infrastructure for tracking active CRTC resources
This provides a cached view of the current screen resources, with the coordinates and refresh rate for every active CRTC. It's currently only implemented for X11/XCB. Fixes:4752655649("egl/x11: implement ANGLE_sync_control_rate") Reviewed-by: Adam Jackson <ajax@redhat.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/20665> (cherry picked from commit3170b63314)
This commit is contained in:
parent
48de75f438
commit
98a6cfd395
4 changed files with 213 additions and 11 deletions
|
|
@ -184,7 +184,7 @@
|
||||||
"description": "loader: Add infrastructure for tracking active CRTC resources",
|
"description": "loader: Add infrastructure for tracking active CRTC resources",
|
||||||
"nominated": true,
|
"nominated": true,
|
||||||
"nomination_type": 1,
|
"nomination_type": 1,
|
||||||
"resolution": 0,
|
"resolution": 1,
|
||||||
"main_sha": null,
|
"main_sha": null,
|
||||||
"because_sha": "47526556494f18cd2c02f978bccac7e2ba73adcd"
|
"because_sha": "47526556494f18cd2c02f978bccac7e2ba73adcd"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -357,15 +357,6 @@ loader_dri3_drawable_fini(struct loader_dri3_drawable *draw)
|
||||||
for (i = 0; i < ARRAY_SIZE(draw->buffers); i++)
|
for (i = 0; i < ARRAY_SIZE(draw->buffers); i++)
|
||||||
dri3_free_render_buffer(draw, i);
|
dri3_free_render_buffer(draw, i);
|
||||||
|
|
||||||
if (draw->special_event) {
|
|
||||||
xcb_void_cookie_t cookie =
|
|
||||||
xcb_present_select_input_checked(draw->conn, draw->eid, draw->drawable,
|
|
||||||
XCB_PRESENT_EVENT_MASK_NO_EVENT);
|
|
||||||
|
|
||||||
xcb_discard_reply(draw->conn, cookie.sequence);
|
|
||||||
xcb_unregister_for_special_event(draw->conn, draw->special_event);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (draw->region)
|
if (draw->region)
|
||||||
xcb_xfixes_destroy_region(draw->conn, draw->region);
|
xcb_xfixes_destroy_region(draw->conn, draw->region);
|
||||||
|
|
||||||
|
|
@ -2350,6 +2341,181 @@ 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
|
* Make sure the server has flushed all pending swap buffers to hardware
|
||||||
|
|
|
||||||
|
|
@ -294,4 +294,40 @@ loader_dri3_swapbuffer_barrier(struct loader_dri3_drawable *draw);
|
||||||
|
|
||||||
void
|
void
|
||||||
loader_dri3_close_screen(__DRIscreen *dri_screen);
|
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
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ if with_platform_x11 and with_dri3
|
||||||
include_directories : [inc_include, inc_src],
|
include_directories : [inc_include, inc_src],
|
||||||
dependencies : [
|
dependencies : [
|
||||||
dep_libdrm, dep_xcb_dri3, dep_xcb_present, dep_xcb_sync, dep_xshmfence,
|
dep_libdrm, dep_xcb_dri3, dep_xcb_present, dep_xcb_sync, dep_xshmfence,
|
||||||
dep_xcb_xfixes,
|
dep_xcb_xfixes, dep_xcb_xrandr,
|
||||||
],
|
],
|
||||||
build_by_default : false,
|
build_by_default : false,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue