mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-07 00:38:48 +02:00
egl: Rewrite eglGetMscRateANGLE to avoid probes and handle multi-monitor
RRGetScreenInfo re-probes connector status, which may result in an EDID transfer for every output, which according to Adam Jackson can be on the order of 100ms for a single EDID block. So our previous implementation of this eglGetMscRateANGLE was blocking for excessive periods of time instead of being a quick query of the refresh rate like users expect. This changes our eglGetMscRateANGLE implementation from using RRGetScreenInfo to RRGetScreenResourcesCurrent and RRGetCrtcInfo. This obtains the same monitor info without re-probing connectors. Fixes a severe performance regression in Chromium WebGL performance. While we're re-implementing the extension, we also implement proper multi-monitor support: if there are multiple active CRTCs, we determine which contains the largest portion of the surface, as specified in the EGL_ANGLE_sync_control_rate extension. We also now report fractional refresh rates correctly rather than rounding to the nearest Hz. Fixes:4752655649("egl/x11: implement ANGLE_sync_control_rate") Closes: https://gitlab.freedesktop.org/mesa/mesa/-/issues/6996 Closes: https://gitlab.freedesktop.org/mesa/mesa/-/issues/7038 Reviewed-by: Adam Jackson <ajax@redhat.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/20665> (cherry picked from commit41d5f0ee09)
This commit is contained in:
parent
987e4f54c0
commit
b52fbf7185
3 changed files with 76 additions and 10 deletions
|
|
@ -4873,7 +4873,7 @@
|
|||
"description": "egl: Rewrite eglGetMscRateANGLE to avoid probes and handle multi-monitor",
|
||||
"nominated": true,
|
||||
"nomination_type": 1,
|
||||
"resolution": 0,
|
||||
"resolution": 1,
|
||||
"main_sha": null,
|
||||
"because_sha": "47526556494f18cd2c02f978bccac7e2ba73adcd"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -274,6 +274,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;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -1191,23 +1191,82 @@ dri2_x11_get_sync_values(_EGLDisplay *display, _EGLSurface *surface,
|
|||
return EGL_TRUE;
|
||||
}
|
||||
|
||||
static int
|
||||
box_intersection_area(int16_t a_x, int16_t a_y,
|
||||
int16_t a_width, int16_t a_height,
|
||||
int16_t b_x, int16_t b_y,
|
||||
int16_t b_width, int16_t b_height)
|
||||
{
|
||||
int w = MIN2(a_x + a_width, b_x + b_width) - MAX2(a_x, b_x);
|
||||
int h = MIN2(a_y + a_height, b_y + b_height) - MAX2(a_y, b_y);
|
||||
|
||||
return (w < 0 || h < 0) ? 0 : w * h;
|
||||
}
|
||||
|
||||
EGLBoolean
|
||||
dri2_x11_get_msc_rate(_EGLDisplay *display, _EGLSurface *surface,
|
||||
EGLint *numerator, EGLint *denominator)
|
||||
{
|
||||
struct dri2_egl_display *dri2_dpy = dri2_egl_display(display);
|
||||
xcb_randr_get_screen_info_cookie_t cookie;
|
||||
xcb_randr_get_screen_info_reply_t *reply;
|
||||
|
||||
cookie = xcb_randr_get_screen_info_unchecked(dri2_dpy->conn, dri2_dpy->screen->root);
|
||||
reply = xcb_randr_get_screen_info_reply(dri2_dpy->conn, cookie, NULL);
|
||||
loader_dri3_update_screen_resources(&dri2_dpy->screen_resources);
|
||||
|
||||
if (!reply)
|
||||
return _eglError(EGL_BAD_ACCESS, "eglGetMscRateANGLE");
|
||||
if (dri2_dpy->screen_resources.num_crtcs == 0) {
|
||||
/* If there's no CRTC active, use the present fake vblank of 1Hz */
|
||||
*numerator = 1;
|
||||
*denominator = 1;
|
||||
return EGL_TRUE;
|
||||
}
|
||||
|
||||
*numerator = reply->rate;
|
||||
*denominator = 1;
|
||||
free(reply);
|
||||
/* Default to the first CRTC in the list */
|
||||
*numerator = dri2_dpy->screen_resources.crtcs[0].refresh_numerator;
|
||||
*denominator = dri2_dpy->screen_resources.crtcs[0].refresh_denominator;
|
||||
|
||||
/* If there's only one active CRTC, we're done */
|
||||
if (dri2_dpy->screen_resources.num_crtcs == 1)
|
||||
return EGL_TRUE;
|
||||
|
||||
/* In a multi-monitor setup, look at each CRTC and perform a box
|
||||
* intersection between the CRTC and surface. Use the CRTC whose
|
||||
* box intersection has the largest area.
|
||||
*/
|
||||
if (surface->Type != EGL_WINDOW_BIT)
|
||||
return EGL_TRUE;
|
||||
|
||||
xcb_window_t window = (uintptr_t) surface->NativeSurface;
|
||||
|
||||
xcb_translate_coordinates_cookie_t cookie =
|
||||
xcb_translate_coordinates_unchecked(dri2_dpy->conn, window,
|
||||
dri2_dpy->screen->root, 0, 0);
|
||||
xcb_translate_coordinates_reply_t *reply =
|
||||
xcb_translate_coordinates_reply(dri2_dpy->conn, cookie, NULL);
|
||||
|
||||
if (!reply) {
|
||||
_eglError(EGL_BAD_SURFACE,
|
||||
"eglGetMscRateANGLE failed to translate coordinates");
|
||||
return EGL_FALSE;
|
||||
}
|
||||
|
||||
int area = 0;
|
||||
|
||||
for (unsigned c = 0; c < dri2_dpy->screen_resources.num_crtcs; c++) {
|
||||
struct loader_dri3_crtc_info *crtc =
|
||||
&dri2_dpy->screen_resources.crtcs[c];
|
||||
|
||||
int c_area = box_intersection_area(reply->dst_x, reply->dst_y,
|
||||
surface->Width, surface->Height,
|
||||
crtc->x, crtc->y,
|
||||
crtc->width, crtc->height);
|
||||
if (c_area > area) {
|
||||
*numerator = crtc->refresh_numerator;
|
||||
*denominator = crtc->refresh_denominator;
|
||||
area = c_area;
|
||||
}
|
||||
}
|
||||
|
||||
/* If the window is entirely off-screen, then area will still be 0.
|
||||
* We defaulted to the first CRTC in the list's refresh rate, earlier.
|
||||
*/
|
||||
|
||||
return EGL_TRUE;
|
||||
}
|
||||
|
|
@ -1582,6 +1641,9 @@ 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);
|
||||
|
||||
dri2_dpy->loader_dri3_ext.core = dri2_dpy->core;
|
||||
dri2_dpy->loader_dri3_ext.image_driver = dri2_dpy->image_driver;
|
||||
dri2_dpy->loader_dri3_ext.flush = dri2_dpy->flush;
|
||||
|
|
@ -1729,6 +1791,9 @@ dri2_initialize_x11(_EGLDisplay *disp)
|
|||
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);
|
||||
|
||||
if (dri2_dpy->own_device)
|
||||
xcb_disconnect(dri2_dpy->conn);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue