Merge branch 'cursor' into 'master'

backend/drm: Fix hardware cursors when rendering to linear is not available

See merge request wlroots/wlroots!4596
This commit is contained in:
Austin Shafer 2024-04-20 15:01:59 +00:00
commit dc2e1b8051
7 changed files with 191 additions and 36 deletions

View file

@ -1005,6 +1005,7 @@ static bool drm_connector_set_cursor(struct wlr_output *output,
struct wlr_drm_connector *conn = get_drm_connector_from_output(output);
struct wlr_drm_backend *drm = conn->backend;
struct wlr_drm_crtc *crtc = conn->crtc;
bool ok = false;
if (!crtc) {
return false;
@ -1033,34 +1034,62 @@ static bool drm_connector_set_cursor(struct wlr_output *output,
return false;
}
struct wlr_buffer *local_buf;
if (drm->parent) {
// First try importing our buffer
struct wlr_buffer *local_buf = wlr_buffer_lock(buffer);
ok = drm_fb_import(&conn->cursor_pending_fb, drm, local_buf,
&plane->formats);
wlr_buffer_unlock(local_buf);
if (!ok) {
// If this failed blit a compatible buffer. This will blit it to
// our mgpu surface in the case that we are a secondary device
struct wlr_drm_format format = {0};
// Try to find a common format/modifier
if (!drm_plane_pick_render_format(plane, &format, &drm->mgpu_renderer)) {
wlr_log(WLR_ERROR, "Failed to pick cursor plane format");
return false;
// If the above failed it may be because the modifier for this
// buffer is not able to be scanned out, as is the case on some
// GPUs. If it failed try to do a linear copy. This will map
// the mgpu surface as a linear texture and read pixels from
// the buffer into it. This avoids a scenario where the
// hardware cannot render to linear textures but only linear
// textures are supported for cursors, as is the case with
// Nvidia and VmWare GPUs
// Create a default format with only the linear modifier
wlr_drm_format_init(&format, DRM_FORMAT_ARGB8888);
if (!wlr_drm_format_add(&format, 0)) {
wlr_drm_format_finish(&format);
return false;
}
}
bool ok = init_drm_surface(&plane->mgpu_surf, &drm->mgpu_renderer,
buffer->width, buffer->height, &format);
ok = init_drm_surface(&plane->mgpu_surf, &drm->mgpu_renderer,
buffer->width, buffer->height, &format);
wlr_drm_format_finish(&format);
if (!ok) {
return false;
}
// First try to blit our cursor image.
local_buf = drm_surface_blit(&plane->mgpu_surf, buffer);
// If this is not possible due to the GPU not being able to
// render to a supported cursor format, then fall back to a
// more expensive copy
if (local_buf == NULL) {
return false;
// use the primary GPU for this, which will either be the current DRM
// backend or the parent if it has one
struct wlr_drm_renderer *drm_renderer =
drm->parent ? &drm->parent->mgpu_renderer : &drm->mgpu_renderer;
local_buf = drm_cursor_copy(&plane->mgpu_surf, drm_renderer, buffer);
if (local_buf == NULL) {
return false;
}
}
} else {
local_buf = wlr_buffer_lock(buffer);
}
bool ok = drm_fb_import(&conn->cursor_pending_fb, drm, local_buf,
&plane->formats);
wlr_buffer_unlock(local_buf);
if (!ok) {
return false;
ok = drm_fb_import(&conn->cursor_pending_fb, drm, local_buf,
&plane->formats);
wlr_buffer_unlock(local_buf);
}
conn->cursor_enabled = true;
@ -1069,7 +1098,7 @@ static bool drm_connector_set_cursor(struct wlr_output *output,
}
wlr_output_update_needs_frame(output);
return true;
return ok;
}
static bool drm_connector_move_cursor(struct wlr_output *output,