mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-08 17:48:10 +02:00
egl/loader: move crtc resource infrastructure as common helper
Patch moves (and renames) the infrastructure to fix compilation
failures when dri3 is not enabled in the build.
Fixes: 3170b63314 ("loader: Add infrastructure for tracking active CRTC resources");
Closes: https://gitlab.freedesktop.org/mesa/mesa/-/issues/8476
Signed-off-by: Tapani Pälli <tapani.palli@intel.com>
Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/22897>
This commit is contained in:
parent
2a1e6a140d
commit
5a7520d252
7 changed files with 235 additions and 219 deletions
|
|
@ -38,6 +38,7 @@
|
|||
#include <xcb/xfixes.h>
|
||||
#include <X11/Xlib-xcb.h>
|
||||
|
||||
#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
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -18,11 +18,45 @@
|
|||
* OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef LOADER_DRI_HELPER_H
|
||||
#define LOADER_DRI_HELPER_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <GL/gl.h> /* dri_interface needs GL types */
|
||||
#include <GL/internal/dri_interface.h>
|
||||
#include <c11/threads.h>
|
||||
|
||||
#ifdef HAVE_X11_PLATFORM
|
||||
#include <xcb/xcb.h>
|
||||
#include <xcb/dri3.h>
|
||||
#include <xcb/present.h>
|
||||
|
||||
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 */
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue