libweston/backends: Move damage flush into backends

Currently we flush damage for the "primary plane" every repaint, but this
is folly.

The drm backend may skip rendering entirely if using an all-planes
composition. This could leave the renderer plane in a messy state if a
surface on an overlay plane disappears.

Instead, let the backends flush the primary plane damage when they know
they need to render.

Fixes #864

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
This commit is contained in:
Derek Foreman 2024-01-10 14:13:09 -06:00
parent 04d9f7e738
commit 2abe4efcf7
12 changed files with 118 additions and 56 deletions

View File

@ -548,7 +548,7 @@ struct weston_output {
struct weston_log_pacer pixman_overdraw_pacer;
int (*start_repaint_loop)(struct weston_output *output);
int (*repaint)(struct weston_output *output, pixman_region32_t *damage);
int (*repaint)(struct weston_output *output);
void (*destroy)(struct weston_output *output);
void (*assign_planes)(struct weston_output *output);
int (*switch_mode)(struct weston_output *output, struct weston_mode *mode);

View File

@ -965,7 +965,7 @@ bool
drm_plane_is_available(struct drm_plane *plane, struct drm_output *output);
void
drm_output_render(struct drm_output_state *state, pixman_region32_t *damage);
drm_output_render(struct drm_output_state *state);
int
parse_gbm_format(const char *s, const struct pixel_format_info *default_format,

View File

@ -202,8 +202,7 @@ drm_virtual_output_submit_frame(struct drm_output *output,
}
static int
drm_virtual_output_repaint(struct weston_output *output_base,
pixman_region32_t *damage)
drm_virtual_output_repaint(struct weston_output *output_base)
{
struct drm_output_state *state = NULL;
struct drm_output *output = to_drm_output(output_base);
@ -237,7 +236,7 @@ drm_virtual_output_repaint(struct weston_output *output_base,
pending_state,
DRM_OUTPUT_STATE_CLEAR_PLANES);
drm_output_render(state, damage);
drm_output_render(state);
scanout_state = drm_output_state_get_plane(state, scanout_plane);
if (!scanout_state || !scanout_state->fb)
goto err;

View File

@ -355,7 +355,7 @@ drm_output_render_pixman(struct drm_output_state *state,
}
void
drm_output_render(struct drm_output_state *state, pixman_region32_t *damage)
drm_output_render(struct drm_output_state *state)
{
struct drm_output *output = state->output;
struct drm_device *device = output->device;
@ -365,7 +365,7 @@ drm_output_render(struct drm_output_state *state, pixman_region32_t *damage)
struct drm_property_info *damage_info =
&scanout_plane->props[WDRM_PLANE_FB_DAMAGE_CLIPS];
struct drm_fb *fb;
pixman_region32_t scanout_damage;
pixman_region32_t damage, scanout_damage;
pixman_box32_t *rects;
int n_rects;
@ -375,6 +375,10 @@ drm_output_render(struct drm_output_state *state, pixman_region32_t *damage)
if (scanout_state->fb)
return;
pixman_region32_init(&damage);
weston_output_flush_damage_for_primary_plane(&output->base, &damage);
/*
* If we don't have any damage on the primary plane, and we already
* have a renderer buffer active, we can reuse it; else we pass
@ -382,7 +386,7 @@ drm_output_render(struct drm_output_state *state, pixman_region32_t *damage)
* area. But, we still have to call the renderer anyway if any screen
* capture is pending, otherwise the capture will not complete.
*/
if (!pixman_region32_not_empty(damage) &&
if (!pixman_region32_not_empty(&damage) &&
wl_list_empty(&output->base.frame_signal.listener_list) &&
!weston_output_has_renderer_capture_tasks(&output->base) &&
scanout_plane->state_cur->fb &&
@ -390,14 +394,14 @@ drm_output_render(struct drm_output_state *state, pixman_region32_t *damage)
scanout_plane->state_cur->fb->type == BUFFER_PIXMAN_DUMB)) {
fb = drm_fb_ref(scanout_plane->state_cur->fb);
} else if (c->renderer->type == WESTON_RENDERER_PIXMAN) {
fb = drm_output_render_pixman(state, damage);
fb = drm_output_render_pixman(state, &damage);
} else {
fb = drm_output_render_gl(state, damage);
fb = drm_output_render_gl(state, &damage);
}
if (!fb) {
drm_plane_state_put_back(scanout_state);
return;
goto out;
}
scanout_state->fb = fb;
@ -417,13 +421,13 @@ drm_output_render(struct drm_output_state *state, pixman_region32_t *damage)
/* Don't bother calculating plane damage if the plane doesn't support it */
if (damage_info->prop_id == 0)
return;
goto out;
pixman_region32_init(&scanout_damage);
weston_region_global_to_output(&scanout_damage,
&output->base,
damage);
&damage);
assert(scanout_state->damage_blob_id == 0);
@ -440,6 +444,8 @@ drm_output_render(struct drm_output_state *state, pixman_region32_t *damage)
&scanout_state->damage_blob_id);
pixman_region32_fini(&scanout_damage);
out:
pixman_region32_fini(&damage);
}
static uint32_t
@ -651,7 +657,7 @@ cursor_bo_update(struct drm_output *output, struct weston_view *ev)
#endif
static int
drm_output_repaint(struct weston_output *output_base, pixman_region32_t *damage)
drm_output_repaint(struct weston_output *output_base)
{
struct drm_output *output = to_drm_output(output_base);
struct drm_output_state *state = NULL;
@ -718,7 +724,7 @@ drm_output_repaint(struct weston_output *output_base, pixman_region32_t *damage)
if (device->atomic_modeset)
drm_output_pick_writeback_capture_task(output);
drm_output_render(state, damage);
drm_output_render(state);
scanout_state = drm_output_state_get_plane(state,
output->scanout_plane);
if (!scanout_state || !scanout_state->fb)

View File

@ -152,11 +152,11 @@ headless_output_update_gl_border(struct headless_output *output)
}
static int
headless_output_repaint(struct weston_output *output_base,
pixman_region32_t *damage)
headless_output_repaint(struct weston_output *output_base)
{
struct headless_output *output = to_headless_output(output_base);
struct weston_compositor *ec;
pixman_region32_t damage;
assert(output);
@ -164,9 +164,15 @@ headless_output_repaint(struct weston_output *output_base,
headless_output_update_gl_border(output);
ec->renderer->repaint_output(&output->base, damage,
pixman_region32_init(&damage);
weston_output_flush_damage_for_primary_plane(output_base, &damage);
ec->renderer->repaint_output(&output->base, &damage,
output->renderbuffer);
pixman_region32_fini(&damage);
wl_event_source_timer_update(output->finish_frame_timer, 16);
return 0;

View File

@ -725,19 +725,24 @@ pipewire_submit_buffer(struct pipewire_output *output,
}
static int
pipewire_output_repaint(struct weston_output *base, pixman_region32_t *damage)
pipewire_output_repaint(struct weston_output *base)
{
struct pipewire_output *output = to_pipewire_output(base);
struct weston_compositor *ec = output->base.compositor;
struct pw_buffer *buffer;
struct pipewire_frame_data *frame_data;
pixman_region32_t damage;
assert(output);
if (pw_stream_get_state(output->stream, NULL) != PW_STREAM_STATE_STREAMING)
goto out;
if (!pixman_region32_not_empty(damage))
pixman_region32_init(&damage);
weston_output_flush_damage_for_primary_plane(base, &damage);
if (!pixman_region32_not_empty(&damage))
goto out;
buffer = pw_stream_dequeue_buffer(output->stream);
@ -748,12 +753,14 @@ pipewire_output_repaint(struct weston_output *base, pixman_region32_t *damage)
pipewire_output_debug(output, "dequeued buffer: %p", buffer);
frame_data = buffer->user_data;
ec->renderer->repaint_output(&output->base, damage, frame_data->renderbuffer);
ec->renderer->repaint_output(&output->base, &damage, frame_data->renderbuffer);
pipewire_submit_buffer(output, buffer);
out:
pixman_region32_fini(&damage);
weston_output_arm_frame_timer(base, output->finish_frame_timer);
return 0;

View File

@ -272,24 +272,29 @@ rdp_output_start_repaint_loop(struct weston_output *output)
}
static int
rdp_output_repaint(struct weston_output *output_base, pixman_region32_t *damage)
rdp_output_repaint(struct weston_output *output_base)
{
struct rdp_output *output = container_of(output_base, struct rdp_output, base);
struct weston_compositor *ec = output->base.compositor;
struct rdp_backend *b = output->backend;
struct rdp_peers_item *peer;
pixman_region32_t damage;
assert(output);
ec->renderer->repaint_output(&output->base, damage,
pixman_region32_init(&damage);
weston_output_flush_damage_for_primary_plane(output_base, &damage);
ec->renderer->repaint_output(&output->base, &damage,
output->renderbuffer);
if (pixman_region32_not_empty(damage)) {
if (pixman_region32_not_empty(&damage)) {
pixman_region32_t transformed_damage;
pixman_region32_init(&transformed_damage);
weston_region_global_to_output(&transformed_damage,
output_base,
damage);
&damage);
wl_list_for_each(peer, &b->peers, link) {
if ((peer->flags & RDP_PEER_ACTIVATED) &&
(peer->flags & RDP_PEER_OUTPUT_ENABLED)) {
@ -299,6 +304,8 @@ rdp_output_repaint(struct weston_output *output_base, pixman_region32_t *damage)
pixman_region32_fini(&transformed_damage);
}
pixman_region32_fini(&damage);
weston_output_arm_frame_timer(output_base, output->finish_frame_timer);
return 0;

View File

@ -1004,10 +1004,11 @@ vnc_output_start_repaint_loop(struct weston_output *output)
}
static int
vnc_output_repaint(struct weston_output *base, pixman_region32_t *damage)
vnc_output_repaint(struct weston_output *base)
{
struct vnc_output *output = to_vnc_output(base);
struct vnc_backend *backend = output->backend;
pixman_region32_t damage;
assert(output);
@ -1016,10 +1017,16 @@ vnc_output_repaint(struct weston_output *base, pixman_region32_t *damage)
vnc_output_update_cursor(output);
if (pixman_region32_not_empty(damage)) {
vnc_update_buffer(output->display, damage);
pixman_region32_init(&damage);
weston_output_flush_damage_for_primary_plane(base, &damage);
if (pixman_region32_not_empty(&damage)) {
vnc_update_buffer(output->display, &damage);
}
pixman_region32_fini(&damage);
/*
* Make sure damage of this (or previous) damage is handled
*

View File

@ -498,22 +498,28 @@ wayland_output_start_repaint_loop(struct weston_output *output_base)
#ifdef ENABLE_EGL
static int
wayland_output_repaint_gl(struct weston_output *output_base,
pixman_region32_t *damage)
wayland_output_repaint_gl(struct weston_output *output_base)
{
struct wayland_output *output = to_wayland_output(output_base);
struct weston_compositor *ec;
pixman_region32_t damage;
assert(output);
ec = output->base.compositor;
pixman_region32_init(&damage);
weston_output_flush_damage_for_primary_plane(output_base, &damage);
output->frame_cb = wl_surface_frame(output->parent.surface);
wl_callback_add_listener(output->frame_cb, &frame_listener, output);
wayland_output_update_gl_border(output);
ec->renderer->repaint_output(&output->base, damage, NULL);
ec->renderer->repaint_output(&output->base, &damage, NULL);
pixman_region32_fini(&damage);
return 0;
}
@ -604,17 +610,21 @@ wayland_shm_buffer_attach(struct wayland_shm_buffer *sb,
}
static int
wayland_output_repaint_pixman(struct weston_output *output_base,
pixman_region32_t *damage)
wayland_output_repaint_pixman(struct weston_output *output_base)
{
struct wayland_output *output = to_wayland_output(output_base);
struct wayland_backend *b;
struct wayland_shm_buffer *sb;
pixman_region32_t damage;
assert(output);
b = output->backend;
pixman_region32_init(&damage);
weston_output_flush_damage_for_primary_plane(output_base, &damage);
if (output->frame) {
if (frame_status(output->frame) & FRAME_STATUS_REPAINT)
wl_list_for_each(sb, &output->shm.buffers, link)
@ -624,10 +634,12 @@ wayland_output_repaint_pixman(struct weston_output *output_base,
sb = wayland_output_get_shm_buffer(output);
wayland_output_update_shm_border(sb);
b->compositor->renderer->repaint_output(output_base, damage,
b->compositor->renderer->repaint_output(output_base, &damage,
sb->renderbuffer);
wayland_shm_buffer_attach(sb, damage);
wayland_shm_buffer_attach(sb, &damage);
pixman_region32_fini(&damage);
output->frame_cb = wl_surface_frame(output->parent.surface);
wl_callback_add_listener(output->frame_cb, &frame_listener, output);

View File

@ -429,17 +429,23 @@ x11_output_start_repaint_loop(struct weston_output *output)
}
static int
x11_output_repaint_gl(struct weston_output *output_base,
pixman_region32_t *damage)
x11_output_repaint_gl(struct weston_output *output_base)
{
struct x11_output *output = to_x11_output(output_base);
struct weston_compositor *ec;
pixman_region32_t damage;
assert(output);
ec = output->base.compositor;
ec->renderer->repaint_output(output_base, damage, NULL);
pixman_region32_init(&damage);
weston_output_flush_damage_for_primary_plane(output_base, &damage);
ec->renderer->repaint_output(output_base, &damage, NULL);
pixman_region32_fini(&damage);
weston_output_arm_frame_timer(output_base, output->finish_frame_timer);
return 0;
@ -498,8 +504,7 @@ set_clip_for_output(struct weston_output *output_base, pixman_region32_t *region
static int
x11_output_repaint_shm(struct weston_output *output_base,
pixman_region32_t *damage)
x11_output_repaint_shm(struct weston_output *output_base)
{
struct x11_output *output = to_x11_output(output_base);
const struct weston_renderer *renderer;
@ -508,6 +513,7 @@ x11_output_repaint_shm(struct weston_output *output_base,
struct x11_backend *b;
xcb_void_cookie_t cookie;
xcb_generic_error_t *err;
pixman_region32_t damage;
assert(output);
@ -517,9 +523,16 @@ x11_output_repaint_shm(struct weston_output *output_base,
image = renderer->pixman->renderbuffer_get_image(output->renderbuffer);
ec->renderer->repaint_output(output_base, damage, output->renderbuffer);
pixman_region32_init(&damage);
weston_output_flush_damage_for_primary_plane(output_base, &damage);
ec->renderer->repaint_output(output_base, &damage, output->renderbuffer);
set_clip_for_output(output_base, &damage);
pixman_region32_fini(&damage);
set_clip_for_output(output_base, damage);
cookie = xcb_shm_put_image_checked(b->conn, output->window, output->gc,
pixman_image_get_width(image),
pixman_image_get_height(image),

View File

@ -327,4 +327,8 @@ weston_output_flush_damage_for_plane(struct weston_output *output,
struct weston_plane *plane,
pixman_region32_t *damage);
void
weston_output_flush_damage_for_primary_plane(struct weston_output *output,
pixman_region32_t *damage);
#endif

View File

@ -3384,6 +3384,20 @@ weston_output_flush_damage_for_plane(struct weston_output *output,
return changed;
}
WL_EXPORT void
weston_output_flush_damage_for_primary_plane(struct weston_output *output,
pixman_region32_t *damage)
{
weston_output_flush_damage_for_plane(output,
&output->primary_plane,
damage);
if (output->full_repaint_needed) {
pixman_region32_copy(damage, &output->region);
output->full_repaint_needed = false;
}
}
static int
weston_output_repaint(struct weston_output *output)
{
@ -3392,7 +3406,6 @@ weston_output_repaint(struct weston_output *output)
struct weston_animation *animation, *next;
struct wl_resource *cb, *cnext;
struct wl_list frame_callback_list;
pixman_region32_t output_damage;
int r;
uint32_t frame_time_msec;
enum weston_hdcp_protection highest_requested = WESTON_HDCP_DISABLE;
@ -3464,19 +3477,7 @@ weston_output_repaint(struct weston_output *output)
output_accumulate_damage(output);
pixman_region32_init(&output_damage);
weston_output_flush_damage_for_plane(output, &output->primary_plane,
&output_damage);
if (output->full_repaint_needed) {
pixman_region32_copy(&output_damage, &output->region);
output->full_repaint_needed = false;
}
r = output->repaint(output, &output_damage);
pixman_region32_fini(&output_damage);
r = output->repaint(output);
output->repaint_needed = false;
if (r == 0)