2018-02-11 12:49:30 +01:00
|
|
|
#include <stddef.h>
|
2018-02-12 21:29:23 +01:00
|
|
|
#include <stdlib.h>
|
2018-02-11 12:49:30 +01:00
|
|
|
#include <time.h>
|
2019-07-27 10:53:54 +02:00
|
|
|
#include <wayland-server-core.h>
|
2018-02-11 12:49:30 +01:00
|
|
|
#include <wlr/types/wlr_output_damage.h>
|
2018-02-12 21:29:23 +01:00
|
|
|
#include <wlr/types/wlr_output.h>
|
2021-07-01 22:36:01 +02:00
|
|
|
#include <wlr/util/box.h>
|
2022-09-21 16:16:53 +02:00
|
|
|
#include "types/wlr_output.h"
|
2018-02-11 12:49:30 +01:00
|
|
|
|
|
|
|
static void output_handle_destroy(struct wl_listener *listener, void *data) {
|
|
|
|
struct wlr_output_damage *output_damage =
|
|
|
|
wl_container_of(listener, output_damage, output_destroy);
|
|
|
|
wlr_output_damage_destroy(output_damage);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void output_handle_mode(struct wl_listener *listener, void *data) {
|
|
|
|
struct wlr_output_damage *output_damage =
|
|
|
|
wl_container_of(listener, output_damage, output_mode);
|
|
|
|
wlr_output_damage_add_whole(output_damage);
|
|
|
|
}
|
|
|
|
|
2019-04-23 19:22:42 +02:00
|
|
|
static void output_handle_needs_frame(struct wl_listener *listener,
|
2019-04-23 18:26:21 +02:00
|
|
|
void *data) {
|
2018-02-11 12:49:30 +01:00
|
|
|
struct wlr_output_damage *output_damage =
|
2019-04-23 19:22:42 +02:00
|
|
|
wl_container_of(listener, output_damage, output_needs_frame);
|
2018-02-11 12:49:30 +01:00
|
|
|
wlr_output_schedule_frame(output_damage->output);
|
|
|
|
}
|
|
|
|
|
2020-03-12 13:08:57 +01:00
|
|
|
static void output_handle_damage(struct wl_listener *listener, void *data) {
|
|
|
|
struct wlr_output_damage *output_damage =
|
|
|
|
wl_container_of(listener, output_damage, output_damage);
|
|
|
|
struct wlr_output_event_damage *event = data;
|
|
|
|
wlr_output_damage_add(output_damage, event->damage);
|
|
|
|
}
|
|
|
|
|
2018-02-11 12:49:30 +01:00
|
|
|
static void output_handle_frame(struct wl_listener *listener, void *data) {
|
|
|
|
struct wlr_output_damage *output_damage =
|
|
|
|
wl_container_of(listener, output_damage, output_frame);
|
|
|
|
|
|
|
|
if (!output_damage->output->enabled) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-08-18 13:16:16 +02:00
|
|
|
wl_signal_emit_mutable(&output_damage->events.frame, output_damage);
|
2018-02-11 12:49:30 +01:00
|
|
|
}
|
|
|
|
|
2021-01-10 17:07:31 +01:00
|
|
|
static void output_handle_precommit(struct wl_listener *listener, void *data) {
|
|
|
|
struct wlr_output_damage *output_damage =
|
|
|
|
wl_container_of(listener, output_damage, output_precommit);
|
2022-05-24 20:41:22 +02:00
|
|
|
const struct wlr_output_event_precommit *event = data;
|
|
|
|
const struct wlr_output_state *state = event->state;
|
2021-01-10 17:07:31 +01:00
|
|
|
struct wlr_output *output = output_damage->output;
|
|
|
|
|
2022-05-24 20:41:22 +02:00
|
|
|
if (state->committed & WLR_OUTPUT_STATE_BUFFER) {
|
2021-01-10 17:07:31 +01:00
|
|
|
// TODO: find a better way to access this info without a precommit
|
|
|
|
// handler
|
2022-09-21 16:16:53 +02:00
|
|
|
output_damage->pending_attach_render =
|
2022-10-07 16:42:32 +02:00
|
|
|
!output_is_direct_scanout(output, state->buffer);
|
2021-01-10 17:07:31 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-23 19:16:08 +02:00
|
|
|
static void output_handle_commit(struct wl_listener *listener, void *data) {
|
|
|
|
struct wlr_output_damage *output_damage =
|
|
|
|
wl_container_of(listener, output_damage, output_commit);
|
2021-01-10 17:00:09 +01:00
|
|
|
struct wlr_output_event_commit *event = data;
|
2019-04-23 19:16:08 +02:00
|
|
|
|
2021-09-07 10:45:05 +02:00
|
|
|
if (event->committed & WLR_OUTPUT_STATE_BUFFER) {
|
|
|
|
pixman_region32_t *prev;
|
|
|
|
if (output_damage->pending_attach_render) {
|
|
|
|
// render-buffers have been swapped, rotate the damage
|
|
|
|
|
|
|
|
// same as decrementing, but works on unsigned integers
|
|
|
|
output_damage->previous_idx += WLR_OUTPUT_DAMAGE_PREVIOUS_LEN - 1;
|
|
|
|
output_damage->previous_idx %= WLR_OUTPUT_DAMAGE_PREVIOUS_LEN;
|
|
|
|
|
|
|
|
prev = &output_damage->previous[output_damage->previous_idx];
|
|
|
|
pixman_region32_copy(prev, &output_damage->current);
|
|
|
|
} else {
|
|
|
|
// accumulate render-buffer damage
|
|
|
|
prev = &output_damage->previous[output_damage->previous_idx];
|
|
|
|
pixman_region32_union(prev, prev, &output_damage->current);
|
|
|
|
}
|
|
|
|
|
|
|
|
pixman_region32_clear(&output_damage->current);
|
2019-04-23 19:16:08 +02:00
|
|
|
}
|
|
|
|
|
2021-09-07 10:45:05 +02:00
|
|
|
if (event->committed & (WLR_OUTPUT_STATE_MODE | WLR_OUTPUT_STATE_SCALE |
|
|
|
|
WLR_OUTPUT_STATE_TRANSFORM)) {
|
|
|
|
wlr_output_damage_add_whole(output_damage);
|
2019-05-25 19:13:36 +02:00
|
|
|
}
|
2019-04-23 19:16:08 +02:00
|
|
|
}
|
|
|
|
|
2018-02-11 12:49:30 +01:00
|
|
|
struct wlr_output_damage *wlr_output_damage_create(struct wlr_output *output) {
|
|
|
|
struct wlr_output_damage *output_damage =
|
|
|
|
calloc(1, sizeof(struct wlr_output_damage));
|
|
|
|
if (output_damage == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
output_damage->output = output;
|
2018-05-05 15:28:55 +02:00
|
|
|
output_damage->max_rects = 20;
|
2018-02-11 12:49:30 +01:00
|
|
|
wl_signal_init(&output_damage->events.frame);
|
|
|
|
wl_signal_init(&output_damage->events.destroy);
|
|
|
|
|
|
|
|
pixman_region32_init(&output_damage->current);
|
|
|
|
for (size_t i = 0; i < WLR_OUTPUT_DAMAGE_PREVIOUS_LEN; ++i) {
|
|
|
|
pixman_region32_init(&output_damage->previous[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
wl_signal_add(&output->events.destroy, &output_damage->output_destroy);
|
|
|
|
output_damage->output_destroy.notify = output_handle_destroy;
|
|
|
|
wl_signal_add(&output->events.mode, &output_damage->output_mode);
|
|
|
|
output_damage->output_mode.notify = output_handle_mode;
|
2019-04-23 19:22:42 +02:00
|
|
|
wl_signal_add(&output->events.needs_frame, &output_damage->output_needs_frame);
|
|
|
|
output_damage->output_needs_frame.notify = output_handle_needs_frame;
|
2020-03-12 13:08:57 +01:00
|
|
|
wl_signal_add(&output->events.damage, &output_damage->output_damage);
|
|
|
|
output_damage->output_damage.notify = output_handle_damage;
|
2018-02-11 12:49:30 +01:00
|
|
|
wl_signal_add(&output->events.frame, &output_damage->output_frame);
|
|
|
|
output_damage->output_frame.notify = output_handle_frame;
|
2021-01-10 17:07:31 +01:00
|
|
|
wl_signal_add(&output->events.precommit, &output_damage->output_precommit);
|
|
|
|
output_damage->output_precommit.notify = output_handle_precommit;
|
2019-04-23 19:16:08 +02:00
|
|
|
wl_signal_add(&output->events.commit, &output_damage->output_commit);
|
|
|
|
output_damage->output_commit.notify = output_handle_commit;
|
2018-02-11 12:49:30 +01:00
|
|
|
|
|
|
|
return output_damage;
|
|
|
|
}
|
|
|
|
|
|
|
|
void wlr_output_damage_destroy(struct wlr_output_damage *output_damage) {
|
|
|
|
if (output_damage == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
2022-08-18 13:16:16 +02:00
|
|
|
wl_signal_emit_mutable(&output_damage->events.destroy, output_damage);
|
2018-02-11 12:49:30 +01:00
|
|
|
wl_list_remove(&output_damage->output_destroy.link);
|
|
|
|
wl_list_remove(&output_damage->output_mode.link);
|
2019-04-23 19:22:42 +02:00
|
|
|
wl_list_remove(&output_damage->output_needs_frame.link);
|
2020-03-12 13:08:57 +01:00
|
|
|
wl_list_remove(&output_damage->output_damage.link);
|
2018-02-11 12:49:30 +01:00
|
|
|
wl_list_remove(&output_damage->output_frame.link);
|
2021-01-10 17:07:31 +01:00
|
|
|
wl_list_remove(&output_damage->output_precommit.link);
|
2019-04-25 09:01:43 +02:00
|
|
|
wl_list_remove(&output_damage->output_commit.link);
|
2018-02-11 12:49:30 +01:00
|
|
|
pixman_region32_fini(&output_damage->current);
|
|
|
|
for (size_t i = 0; i < WLR_OUTPUT_DAMAGE_PREVIOUS_LEN; ++i) {
|
|
|
|
pixman_region32_fini(&output_damage->previous[i]);
|
|
|
|
}
|
|
|
|
free(output_damage);
|
|
|
|
}
|
|
|
|
|
2019-04-23 19:16:08 +02:00
|
|
|
bool wlr_output_damage_attach_render(struct wlr_output_damage *output_damage,
|
2019-04-23 19:22:42 +02:00
|
|
|
bool *needs_frame, pixman_region32_t *damage) {
|
2018-02-11 12:49:30 +01:00
|
|
|
struct wlr_output *output = output_damage->output;
|
|
|
|
|
|
|
|
int buffer_age = -1;
|
2019-04-22 11:42:37 +02:00
|
|
|
if (!wlr_output_attach_render(output, &buffer_age)) {
|
2018-02-11 12:49:30 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-06-24 16:57:45 +02:00
|
|
|
*needs_frame =
|
|
|
|
output->needs_frame || pixman_region32_not_empty(&output_damage->current);
|
2018-02-11 12:49:30 +01:00
|
|
|
// Check if we can use damage tracking
|
|
|
|
if (buffer_age <= 0 || buffer_age - 1 > WLR_OUTPUT_DAMAGE_PREVIOUS_LEN) {
|
|
|
|
int width, height;
|
|
|
|
wlr_output_transformed_resolution(output, &width, &height);
|
|
|
|
|
|
|
|
// Buffer new or too old, damage the whole output
|
|
|
|
pixman_region32_union_rect(damage, damage, 0, 0, width, height);
|
2019-06-24 16:57:45 +02:00
|
|
|
*needs_frame = true;
|
2018-02-11 12:49:30 +01:00
|
|
|
} else {
|
|
|
|
pixman_region32_copy(damage, &output_damage->current);
|
|
|
|
|
|
|
|
// Accumulate damage from old buffers
|
|
|
|
size_t idx = output_damage->previous_idx;
|
|
|
|
for (int i = 0; i < buffer_age - 1; ++i) {
|
|
|
|
int j = (idx + i) % WLR_OUTPUT_DAMAGE_PREVIOUS_LEN;
|
|
|
|
pixman_region32_union(damage, damage, &output_damage->previous[j]);
|
|
|
|
}
|
2018-05-05 15:28:55 +02:00
|
|
|
|
|
|
|
// Check the number of rectangles
|
|
|
|
int n_rects = pixman_region32_n_rects(damage);
|
|
|
|
if (n_rects > output_damage->max_rects) {
|
|
|
|
pixman_box32_t *extents = pixman_region32_extents(damage);
|
|
|
|
pixman_region32_union_rect(damage, damage, extents->x1, extents->y1,
|
|
|
|
extents->x2 - extents->x1, extents->y2 - extents->y1);
|
|
|
|
}
|
2018-02-11 12:49:30 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void wlr_output_damage_add(struct wlr_output_damage *output_damage,
|
|
|
|
pixman_region32_t *damage) {
|
|
|
|
int width, height;
|
|
|
|
wlr_output_transformed_resolution(output_damage->output, &width, &height);
|
|
|
|
|
2022-02-27 03:51:53 +01:00
|
|
|
pixman_region32_t clipped_damage;
|
|
|
|
pixman_region32_init(&clipped_damage);
|
|
|
|
pixman_region32_intersect_rect(&clipped_damage, damage, 0, 0, width, height);
|
|
|
|
|
|
|
|
if (pixman_region32_not_empty(&clipped_damage)) {
|
|
|
|
pixman_region32_union(&output_damage->current, &output_damage->current,
|
|
|
|
&clipped_damage);
|
|
|
|
wlr_output_schedule_frame(output_damage->output);
|
|
|
|
}
|
|
|
|
|
|
|
|
pixman_region32_fini(&clipped_damage);
|
2018-02-11 12:49:30 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void wlr_output_damage_add_whole(struct wlr_output_damage *output_damage) {
|
|
|
|
int width, height;
|
|
|
|
wlr_output_transformed_resolution(output_damage->output, &width, &height);
|
|
|
|
|
|
|
|
pixman_region32_union_rect(&output_damage->current, &output_damage->current,
|
|
|
|
0, 0, width, height);
|
|
|
|
|
|
|
|
wlr_output_schedule_frame(output_damage->output);
|
|
|
|
}
|
|
|
|
|
|
|
|
void wlr_output_damage_add_box(struct wlr_output_damage *output_damage,
|
|
|
|
struct wlr_box *box) {
|
2022-02-27 03:50:41 +01:00
|
|
|
pixman_region32_t damage;
|
|
|
|
pixman_region32_init_rect(&damage,
|
2018-02-11 12:49:30 +01:00
|
|
|
box->x, box->y, box->width, box->height);
|
2022-02-27 03:50:41 +01:00
|
|
|
wlr_output_damage_add(output_damage, &damage);
|
|
|
|
pixman_region32_fini(&damage);
|
2018-02-11 12:49:30 +01:00
|
|
|
}
|