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:
parent
04d9f7e738
commit
2abe4efcf7
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
*
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue