mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2024-11-21 22:52:20 +00:00
backend/drm: add support for SIZE_HINTS property
This property allows the driver to advertise support for multiple cursor sizes. On Intel, using a smaller buffer size reduces power consumption. References: https://lore.kernel.org/dri-devel/20240227193523.5601-2-ville.syrjala@linux.intel.com/
This commit is contained in:
parent
6f63f55ace
commit
a35b4f059d
@ -135,6 +135,26 @@ bool check_drm_features(struct wlr_drm_backend *drm) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool init_plane_cursor_sizes(struct wlr_drm_plane *plane,
|
||||||
|
const struct drm_plane_size_hint *hints, size_t hints_len) {
|
||||||
|
assert(hints_len > 0);
|
||||||
|
plane->cursor_sizes = calloc(hints_len, sizeof(plane->cursor_sizes[0]));
|
||||||
|
if (plane->cursor_sizes == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
plane->cursor_sizes_len = hints_len;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < hints_len; i++) {
|
||||||
|
const struct drm_plane_size_hint hint = hints[i];
|
||||||
|
plane->cursor_sizes[i] = (struct wlr_output_cursor_size){
|
||||||
|
.width = hint.width,
|
||||||
|
.height = hint.height,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static bool init_plane(struct wlr_drm_backend *drm,
|
static bool init_plane(struct wlr_drm_backend *drm,
|
||||||
struct wlr_drm_plane *p, const drmModePlane *drm_plane) {
|
struct wlr_drm_plane *p, const drmModePlane *drm_plane) {
|
||||||
uint32_t id = drm_plane->plane_id;
|
uint32_t id = drm_plane->plane_id;
|
||||||
@ -186,6 +206,37 @@ static bool init_plane(struct wlr_drm_backend *drm,
|
|||||||
drmModeFreePropertyBlob(blob);
|
drmModeFreePropertyBlob(blob);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t size_hints_blob_id = 0;
|
||||||
|
if (p->props.size_hints) {
|
||||||
|
if (!get_drm_prop(drm->fd, p->id, p->props.size_hints, &size_hints_blob_id)) {
|
||||||
|
wlr_log(WLR_ERROR, "Failed to read SIZE_HINTS property");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (size_hints_blob_id != 0) {
|
||||||
|
drmModePropertyBlobRes *blob = drmModeGetPropertyBlob(drm->fd, size_hints_blob_id);
|
||||||
|
if (!blob) {
|
||||||
|
wlr_log(WLR_ERROR, "Failed to read SIZE_HINTS blob");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct drm_plane_size_hint *size_hints = blob->data;
|
||||||
|
size_t size_hints_len = blob->length / sizeof(size_hints[0]);
|
||||||
|
if (!init_plane_cursor_sizes(p, size_hints, size_hints_len)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
drmModeFreePropertyBlob(blob);
|
||||||
|
} else {
|
||||||
|
const struct drm_plane_size_hint size_hint = {
|
||||||
|
.width = drm->cursor_width,
|
||||||
|
.height = drm->cursor_height,
|
||||||
|
};
|
||||||
|
if (!init_plane_cursor_sizes(p, &size_hint, 1)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
assert(drm->num_crtcs <= 32);
|
assert(drm->num_crtcs <= 32);
|
||||||
for (size_t j = 0; j < drm->num_crtcs; j++) {
|
for (size_t j = 0; j < drm->num_crtcs; j++) {
|
||||||
uint32_t crtc_bit = 1 << j;
|
uint32_t crtc_bit = 1 << j;
|
||||||
@ -1003,8 +1054,15 @@ static bool drm_connector_set_cursor(struct wlr_output *output,
|
|||||||
conn->cursor_enabled = false;
|
conn->cursor_enabled = false;
|
||||||
drm_fb_clear(&conn->cursor_pending_fb);
|
drm_fb_clear(&conn->cursor_pending_fb);
|
||||||
if (buffer != NULL) {
|
if (buffer != NULL) {
|
||||||
if ((uint64_t)buffer->width != drm->cursor_width ||
|
bool found = false;
|
||||||
(uint64_t)buffer->height != drm->cursor_height) {
|
for (size_t i = 0; i < plane->cursor_sizes_len; i++) {
|
||||||
|
struct wlr_output_cursor_size size = plane->cursor_sizes[i];
|
||||||
|
if (size.width == buffer->width && size.height == buffer->height) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
wlr_drm_conn_log(conn, WLR_DEBUG, "Cursor buffer size mismatch");
|
wlr_drm_conn_log(conn, WLR_DEBUG, "Cursor buffer size mismatch");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -1130,11 +1188,18 @@ static const struct wlr_drm_format_set *drm_connector_get_cursor_formats(
|
|||||||
return &plane->formats;
|
return &plane->formats;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void drm_connector_get_cursor_size(struct wlr_output *output,
|
static const struct wlr_output_cursor_size *drm_connector_get_cursor_sizes(struct wlr_output *output,
|
||||||
int *width, int *height) {
|
size_t *len) {
|
||||||
struct wlr_drm_backend *drm = get_drm_backend_from_backend(output->backend);
|
struct wlr_drm_connector *conn = get_drm_connector_from_output(output);
|
||||||
*width = (int)drm->cursor_width;
|
if (!drm_connector_alloc_crtc(conn)) {
|
||||||
*height = (int)drm->cursor_height;
|
return NULL;
|
||||||
|
}
|
||||||
|
struct wlr_drm_plane *plane = conn->crtc->cursor;
|
||||||
|
if (!plane) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
*len = plane->cursor_sizes_len;
|
||||||
|
return plane->cursor_sizes;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct wlr_drm_format_set *drm_connector_get_primary_formats(
|
static const struct wlr_drm_format_set *drm_connector_get_primary_formats(
|
||||||
@ -1160,7 +1225,7 @@ static const struct wlr_output_impl output_impl = {
|
|||||||
.commit = drm_connector_commit,
|
.commit = drm_connector_commit,
|
||||||
.get_gamma_size = drm_connector_get_gamma_size,
|
.get_gamma_size = drm_connector_get_gamma_size,
|
||||||
.get_cursor_formats = drm_connector_get_cursor_formats,
|
.get_cursor_formats = drm_connector_get_cursor_formats,
|
||||||
.get_cursor_size = drm_connector_get_cursor_size,
|
.get_cursor_sizes = drm_connector_get_cursor_sizes,
|
||||||
.get_primary_formats = drm_connector_get_primary_formats,
|
.get_primary_formats = drm_connector_get_primary_formats,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -56,6 +56,7 @@ static const struct prop_info plane_info[] = {
|
|||||||
{ "HOTSPOT_X", INDEX(hotspot_x) },
|
{ "HOTSPOT_X", INDEX(hotspot_x) },
|
||||||
{ "HOTSPOT_Y", INDEX(hotspot_y) },
|
{ "HOTSPOT_Y", INDEX(hotspot_y) },
|
||||||
{ "IN_FORMATS", INDEX(in_formats) },
|
{ "IN_FORMATS", INDEX(in_formats) },
|
||||||
|
{ "SIZE_HINTS", INDEX(size_hints) },
|
||||||
{ "SRC_H", INDEX(src_h) },
|
{ "SRC_H", INDEX(src_h) },
|
||||||
{ "SRC_W", INDEX(src_w) },
|
{ "SRC_W", INDEX(src_w) },
|
||||||
{ "SRC_X", INDEX(src_x) },
|
{ "SRC_X", INDEX(src_x) },
|
||||||
|
@ -29,6 +29,9 @@ struct wlr_drm_plane {
|
|||||||
|
|
||||||
struct wlr_drm_format_set formats;
|
struct wlr_drm_format_set formats;
|
||||||
|
|
||||||
|
struct wlr_output_cursor_size *cursor_sizes;
|
||||||
|
size_t cursor_sizes_len;
|
||||||
|
|
||||||
struct wlr_drm_plane_props props;
|
struct wlr_drm_plane_props props;
|
||||||
|
|
||||||
uint32_t initial_crtc_id;
|
uint32_t initial_crtc_id;
|
||||||
|
@ -44,6 +44,7 @@ struct wlr_drm_plane_props {
|
|||||||
uint32_t type;
|
uint32_t type;
|
||||||
uint32_t rotation; // Not guaranteed to exist
|
uint32_t rotation; // Not guaranteed to exist
|
||||||
uint32_t in_formats; // Not guaranteed to exist
|
uint32_t in_formats; // Not guaranteed to exist
|
||||||
|
uint32_t size_hints; // Not guaranteed to exist
|
||||||
|
|
||||||
// atomic-modesetting only
|
// atomic-modesetting only
|
||||||
|
|
||||||
|
@ -25,6 +25,10 @@
|
|||||||
WLR_OUTPUT_STATE_SUBPIXEL | \
|
WLR_OUTPUT_STATE_SUBPIXEL | \
|
||||||
WLR_OUTPUT_STATE_LAYERS)
|
WLR_OUTPUT_STATE_LAYERS)
|
||||||
|
|
||||||
|
struct wlr_output_cursor_size {
|
||||||
|
int width, height;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A backend implementation of struct wlr_output.
|
* A backend implementation of struct wlr_output.
|
||||||
*
|
*
|
||||||
@ -82,10 +86,11 @@ struct wlr_output_impl {
|
|||||||
const struct wlr_drm_format_set *(*get_cursor_formats)(
|
const struct wlr_drm_format_set *(*get_cursor_formats)(
|
||||||
struct wlr_output *output, uint32_t buffer_caps);
|
struct wlr_output *output, uint32_t buffer_caps);
|
||||||
/**
|
/**
|
||||||
* Get the size suitable for the cursor buffer. Attempts to use a different
|
* Get the list of sizes suitable for the cursor buffer. Attempts to use a
|
||||||
* size for the cursor may fail.
|
* different size for the cursor may fail.
|
||||||
*/
|
*/
|
||||||
void (*get_cursor_size)(struct wlr_output *output, int *width, int *height);
|
const struct wlr_output_cursor_size *(*get_cursor_sizes)(struct wlr_output *output,
|
||||||
|
size_t *len);
|
||||||
/**
|
/**
|
||||||
* Get the list of DRM formats suitable for the primary buffer,
|
* Get the list of DRM formats suitable for the primary buffer,
|
||||||
* assuming a buffer with the specified capabilities.
|
* assuming a buffer with the specified capabilities.
|
||||||
|
@ -111,7 +111,7 @@ wayland_server = dependency('wayland-server',
|
|||||||
)
|
)
|
||||||
|
|
||||||
drm = dependency('libdrm',
|
drm = dependency('libdrm',
|
||||||
version: '>=2.4.120',
|
version: '>=2.4.122',
|
||||||
fallback: 'libdrm',
|
fallback: 'libdrm',
|
||||||
default_options: [
|
default_options: [
|
||||||
'auto_features=disabled',
|
'auto_features=disabled',
|
||||||
|
@ -196,13 +196,27 @@ static struct wlr_buffer *render_cursor_buffer(struct wlr_output_cursor *cursor)
|
|||||||
|
|
||||||
int width = cursor->width;
|
int width = cursor->width;
|
||||||
int height = cursor->height;
|
int height = cursor->height;
|
||||||
if (output->impl->get_cursor_size) {
|
if (output->impl->get_cursor_sizes) {
|
||||||
// Apply hardware limitations on buffer size
|
// Apply hardware limitations on buffer size
|
||||||
output->impl->get_cursor_size(cursor->output, &width, &height);
|
size_t sizes_len = 0;
|
||||||
if ((int)texture->width > width || (int)texture->height > height) {
|
const struct wlr_output_cursor_size *sizes =
|
||||||
|
output->impl->get_cursor_sizes(cursor->output, &sizes_len);
|
||||||
|
|
||||||
|
bool found = false;
|
||||||
|
for (size_t i = 0; i < sizes_len; i++) {
|
||||||
|
struct wlr_output_cursor_size size = sizes[i];
|
||||||
|
if ((int)texture->width <= size.width && (int)texture->height <= size.height) {
|
||||||
|
width = size.width;
|
||||||
|
height = size.height;
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
wlr_log(WLR_DEBUG, "Cursor texture too large (%dx%d), "
|
wlr_log(WLR_DEBUG, "Cursor texture too large (%dx%d), "
|
||||||
"exceeds hardware limitations (%dx%d)", texture->width,
|
"exceeds hardware limitations", texture->width,
|
||||||
texture->height, width, height);
|
texture->height);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user