Merge branch 'drm-offload-background-color' into 'main'

Draft: backend-drm: Add support for the BACKGROUND_COLOR CRTC property

See merge request wayland/weston!1845
This commit is contained in:
Robert Mader 2025-12-19 22:47:53 +01:00
commit 8584e65e15
6 changed files with 82 additions and 17 deletions

View file

@ -562,6 +562,8 @@ struct drm_crtc {
/* CRTC prop WDRM_CRTC_GAMMA_LUT_SIZE */
uint32_t lut_size;
uint64_t background_color;
};
struct drm_output {
@ -725,6 +727,9 @@ drm_output_get_plane_type_name(struct drm_plane *p)
struct drm_crtc *
drm_crtc_find(struct drm_device *device, uint32_t crtc_id);
bool
drm_crtc_supports_background_color(struct drm_crtc *crtc);
struct drm_head *
drm_head_find_by_connector(struct drm_backend *backend, struct drm_device *device, uint32_t connector_id);

View file

@ -197,5 +197,6 @@ enum wdrm_crtc_property {
WDRM_CRTC_GAMMA_LUT,
WDRM_CRTC_GAMMA_LUT_SIZE,
WDRM_CRTC_VRR_ENABLED,
WDRM_CRTC_BACKGROUND_COLOR,
WDRM_CRTC__COUNT
};

View file

@ -2437,6 +2437,10 @@ drm_crtc_create(struct drm_device *device, uint32_t crtc_id, uint32_t pipe)
drm_property_get_value(&crtc->props_crtc[WDRM_CRTC_GAMMA_LUT_SIZE],
props, 0);
crtc->background_color =
drm_property_get_value(&crtc->props_crtc[WDRM_CRTC_BACKGROUND_COLOR],
props, 0);
/* Add it to the last position of the DRM-backend CRTC list */
wl_list_insert(device->crtc_list.prev, &crtc->link);

View file

@ -263,6 +263,7 @@ const struct drm_property_info crtc_props[] = {
[WDRM_CRTC_GAMMA_LUT] = { .name = "GAMMA_LUT", },
[WDRM_CRTC_GAMMA_LUT_SIZE] = { .name = "GAMMA_LUT_SIZE", },
[WDRM_CRTC_VRR_ENABLED] = { .name = "VRR_ENABLED", },
[WDRM_CRTC_BACKGROUND_COLOR] = { .name = "BACKGROUND_COLOR", },
};
@ -1035,6 +1036,15 @@ crtc_add_prop_zero_ok(drmModeAtomicReq *req, struct drm_crtc *crtc,
return crtc_add_prop(req, crtc, prop, val);
}
bool
drm_crtc_supports_background_color(struct drm_crtc *crtc)
{
if (crtc->props_crtc[WDRM_CRTC_BACKGROUND_COLOR].prop_id != 0)
return true;
return true;
}
static int
connector_add_prop(drmModeAtomicReq *req, struct drm_connector *connector,
enum wdrm_connector_property prop, uint64_t val)
@ -1334,6 +1344,21 @@ drm_output_apply_state_atomic(struct drm_output_state *state,
ret |= crtc_add_prop_zero_ok(req, crtc, WDRM_CRTC_VRR_ENABLED,
wdrm_vrr_enabled_from_output(output));
{
struct drm_property_info *info = &crtc->props_crtc[WDRM_CRTC_BACKGROUND_COLOR];
if (info->prop_id == 0)
drm_debug(b, "\t\t\t[CRTC:%lu] %lu (%s) -> %llu (0x%llx) (not supported by driver)\n",
(unsigned long) crtc->crtc_id,
(unsigned long) info->prop_id, info->name,
(unsigned long long) crtc->background_color,
(unsigned long long) crtc->background_color);
else
ret |= crtc_add_prop_zero_ok(req, crtc,
WDRM_CRTC_BACKGROUND_COLOR,
crtc->background_color);
}
/* No need for the DPMS property, since it is implicit in
* routing and CRTC activity. */
wl_list_for_each(head, &output->base.head_list, base.output_link) {

View file

@ -794,13 +794,11 @@ drm_output_find_plane_for_view(struct drm_output_state *state,
}
static bool
is_paint_node_solid_opaque_black(struct weston_paint_node *pnode)
is_paint_node_solid_opaque(struct weston_paint_node *pnode)
{
return pnode->draw_solid && pnode->is_fully_opaque &&
pnode->valid_transform &&
(pnode->surf_xform_valid && !pnode->surf_xform.transform) &&
pnode->solid.r == 0.0f && pnode->solid.g == 0.0f &&
pnode->solid.b == 0.0f;
(pnode->surf_xform_valid && !pnode->surf_xform.transform);
}
static bool
@ -812,12 +810,15 @@ lower_solid_views_to_background_region(struct drm_output *output,
struct drm_backend *b = device->backend;
struct weston_paint_node **visible_pnode;
struct wl_array visible_pnodes_new;
struct weston_solid_buffer_values background_region_color = {0};
wl_array_init(&visible_pnodes_new);
wl_array_for_each(visible_pnode, visible_pnodes) {
struct weston_paint_node *pnode = *visible_pnode;
struct weston_paint_node **visible_pnode_new;
struct weston_view *ev = pnode->view;
bool background_color_matches;
bool background_color_supported;
pixman_region32_t tmp;
drm_debug(b, "\t\t\t[view] evaluating view %p for scene"
@ -825,7 +826,21 @@ lower_solid_views_to_background_region(struct drm_output *output,
ev, output->base.name,
(unsigned long) output->base.id);
if (is_paint_node_solid_opaque_black(pnode)) {
background_color_matches =
is_paint_node_solid_opaque(pnode) &&
(!pixman_region32_not_empty(background_region) ||
(background_region_color.r == pnode->solid.r &&
background_region_color.g == pnode->solid.g &&
background_region_color.b == pnode->solid.b));
background_color_supported =
is_paint_node_solid_opaque(pnode) &&
(drm_crtc_supports_background_color(output->crtc) ||
(pnode->solid.r == 0.0f &&
pnode->solid.g == 0.0f &&
pnode->solid.b == 0.0f));
if (background_color_matches && background_color_supported) {
drm_debug(b, "\t\t\t\t[view] ignoring view %p " \
"(opaque-black solid buffer r %f g %f b %f " \
"a %f)\n",
@ -835,15 +850,31 @@ lower_solid_views_to_background_region(struct drm_output *output,
pixman_region32_union(background_region,
background_region,
&pnode->visible);
background_region_color.a = 1.0f;
background_region_color.r = pnode->solid.r;
background_region_color.g = pnode->solid.g;
background_region_color.b = pnode->solid.b;
if (drm_crtc_supports_background_color(output->crtc)) {
uint64_t a16, r16, g16, b16;
a16 = 0xffff;
r16 = 0xffff * background_region_color.r;
g16 = 0xffff * background_region_color.g;
b16 = 0xffff * background_region_color.b;
output->crtc->background_color =
a16 << 48 | r16 << 32 | g16 << 16 | b16;
}
continue;
}
/* We can support this with the 'CRTC background colour'
* property */
if (pnode->draw_solid) {
drm_debug(b, "\t\t\t\t[view] not assigning view %p to "
"a plane (non-opaque-black solid buffer r %f "
"g %f b %f a %f)\n",
"a plane (background-incompatible solid "
"buffer r %f g %f b %f a %f)\n",
ev, pnode->solid.r, pnode->solid.g,
pnode->solid.b, pnode->solid.a);
wl_array_release(&visible_pnodes_new);
@ -1149,6 +1180,9 @@ drm_output_propose_state(struct weston_output *output_base,
*
* See https://dri.freedesktop.org/docs/drm/gpu/drm-kms.html#plane-abstraction
*
* For other colors the same applies if the BACKGROUND_COLOR DRM
* property is supported.
*
* All said views can thus be ignored during plane assignment.
*/
pixman_region32_init(&background_region);

View file

@ -430,10 +430,8 @@ TEST(drm_offload_fullscreen_semi_transparent_black_background) {
/*
* Test that a fullscreen client with opaque-white single-pixel-buffer with a
* smaller-than-fullscreen-sized dmabuf subsurface above is *not* presented via
* smaller-than-fullscreen-sized dmabuf subsurface above is presented via
* direct-scanout.
*
* This should be optimized in the future.
*/
TEST(drm_offload_fullscreen_semi_transparent_white_background) {
struct xdg_client *xdg_client;
@ -501,7 +499,7 @@ TEST(drm_offload_fullscreen_semi_transparent_white_background) {
wl_surface_commit(overlay_surface);
wl_surface_commit(surface);
presentation_wait_nofail(client, &result);
test_assert_enum(result, FB_PRESENTED);
test_assert_enum(result, FB_PRESENTED_ZERO_COPY);
wp_viewport_destroy(viewport);
wl_subsurface_destroy(overlay_subsurface);
@ -770,9 +768,7 @@ TEST(drm_offload_fullscreen_black_background_red_subsurface_underlay) {
/*
* Test that a windowed / not-fullscreen client on top of a solid background is
* *not* presented via direct-scanout.
*
* This should be optimized in the future.
* presented via direct-scanout.
*/
TEST(drm_offload_windowed) {
struct xdg_client *xdg_client;
@ -816,7 +812,7 @@ TEST(drm_offload_windowed) {
&result);
wl_surface_commit(surface);
presentation_wait_nofail(client, &result);
test_assert_enum(result, FB_PRESENTED);
test_assert_enum(result, FB_PRESENTED_ZERO_COPY);
client_buffer_util_destroy_buffer(buffer);
destroy_xdg_surface(xdg_surface);