screencast: send damage via pw

This commit is contained in:
vaxerski 2023-04-14 17:27:28 +01:00
parent 7fc2e78581
commit a7b7880172
4 changed files with 75 additions and 10 deletions

View file

@ -63,7 +63,8 @@ struct xdpw_frame {
bool y_invert;
uint64_t tv_sec;
uint32_t tv_nsec;
struct xdpw_frame_damage damage;
struct xdpw_frame_damage damage[4];
uint32_t damage_count;
struct xdpw_buffer *xdpw_buffer;
struct pw_buffer *pw_buffer;
};
@ -228,6 +229,8 @@ uint32_t xdpw_format_drm_fourcc_from_wl_shm(enum wl_shm_format format);
enum spa_video_format xdpw_format_pw_from_drm_fourcc(uint32_t format);
enum spa_video_format xdpw_format_pw_strip_alpha(enum spa_video_format format);
struct xdpw_frame_damage merge_damage(struct xdpw_frame_damage *damage1, struct xdpw_frame_damage *damage2);
enum xdpw_chooser_types get_chooser_type(const char *chooser_type);
const char *chooser_type_str(enum xdpw_chooser_types chooser_type);
#endif /* SCREENCAST_COMMON_H */

View file

@ -316,9 +316,18 @@ fixate_format:
SPA_PARAM_META_type, SPA_POD_Id(SPA_META_Header),
SPA_PARAM_META_size, SPA_POD_Int(sizeof(struct spa_meta_header)));
pw_stream_update_params(stream, params, 2);
params[2] = spa_pod_builder_add_object(&b[2].b,
SPA_TYPE_OBJECT_ParamMeta, SPA_PARAM_Meta,
SPA_PARAM_META_type, SPA_POD_Id(SPA_META_VideoDamage),
SPA_PARAM_META_size, SPA_POD_CHOICE_RANGE_Int(
sizeof(struct spa_meta_region) * 4,
sizeof(struct spa_meta_region) * 1,
sizeof(struct spa_meta_region) * 4));
pw_stream_update_params(stream, params, 3);
spa_pod_dynamic_builder_clean(&b[0]);
spa_pod_dynamic_builder_clean(&b[1]);
spa_pod_dynamic_builder_clean(&b[2]);
}
static void pwr_handle_stream_add_buffer(void *data, struct pw_buffer *buffer) {
@ -438,6 +447,38 @@ void xdpw_pwr_enqueue_buffer(struct xdpw_screencast_instance *cast) {
logprint(TRACE, "pipewire: timestamp %"PRId64, h->pts);
}
struct spa_meta *damage;
if ((damage = spa_buffer_find_meta(spa_buf, SPA_META_VideoDamage))) {
struct spa_region *d_region = spa_meta_first(damage);
uint32_t damage_counter = 0;
do {
if (damage_counter >= cast->current_frame.damage_count) {
*d_region = SPA_REGION(0, 0, 0, 0);
logprint(TRACE, "pipewire: end damage %u %u,%u (%ux%u)", damage_counter,
d_region->position.x, d_region->position.y, d_region->size.width, d_region->size.height);
break;
}
*d_region = SPA_REGION(cast->current_frame.damage[damage_counter].x,
cast->current_frame.damage[damage_counter].y,
cast->current_frame.damage[damage_counter].width,
cast->current_frame.damage[damage_counter].height);
logprint(TRACE, "pipewire: damage %u %u,%u (%ux%u)", damage_counter,
d_region->position.x, d_region->position.y, d_region->size.width, d_region->size.height);
damage_counter++;
} while (spa_meta_check(d_region + 1, damage) && d_region++);
if (damage_counter < cast->current_frame.damage_count) {
struct xdpw_frame_damage damage =
{d_region->position.x, d_region->position.x, d_region->size.width, d_region->size.height};
for (; damage_counter < cast->current_frame.damage_count; damage_counter++) {
damage = merge_damage(&damage, &cast->current_frame.damage[damage_counter]);
}
*d_region = SPA_REGION(damage.x, damage.y, damage.width, damage.height);
logprint(TRACE, "pipewire: collected damage %u %u,%u (%ux%u)", damage_counter,
d_region->position.x, d_region->position.y, d_region->size.width, d_region->size.height);
}
}
if (buffer_corrupt) {
for (uint32_t plane = 0; plane < spa_buf->n_datas; plane++) {
d[plane].chunk->flags = SPA_CHUNK_FLAG_CORRUPTED;

View file

@ -410,3 +410,17 @@ const char *chooser_type_str(enum xdpw_chooser_types chooser_type) {
fprintf(stderr, "Could not find chooser type %d\n", chooser_type);
abort();
}
struct xdpw_frame_damage merge_damage(struct xdpw_frame_damage *damage1, struct xdpw_frame_damage *damage2) {
struct xdpw_frame_damage damage;
uint32_t x0, y0;
damage.x = damage1->x < damage2->y ? damage1->x : damage2->x;
damage.y = damage1->y < damage2->y ? damage1->y : damage2->y;
x0 = damage1->x + damage1->width < damage2->x + damage2->width ? damage2->x + damage2->width : damage1->x + damage1->width;
y0 = damage1->y + damage1->height < damage2->y + damage2->height ? damage2->y + damage2->height : damage1->y + damage1->height;
damage.width = x0 - damage.x;
damage.height = y0 - damage.y;
return damage;
}

View file

@ -284,6 +284,7 @@ static void wlr_frame_buffer_done(void *data, struct zwlr_screencopy_frame_v1 *f
return;
}
cast->current_frame.damage_count = 0;
zwlr_screencopy_frame_v1_copy_with_damage(frame, cast->current_frame.xdpw_buffer->buffer);
logprint(TRACE, "wlroots: frame copied");
@ -308,10 +309,13 @@ static void wlr_frame_damage(void *data, struct zwlr_screencopy_frame_v1 *frame,
logprint(TRACE, "wlroots: damage event handler");
cast->current_frame.damage.x = x;
cast->current_frame.damage.y = y;
cast->current_frame.damage.width = width;
cast->current_frame.damage.height = height;
logprint(TRACE, "wlroots: damage %"PRIu32": %"PRIu32",%"PRIu32"x%"PRIu32",%"PRIu32, cast->current_frame.damage_count, x, y, width, height);
struct xdpw_frame_damage damage = {x, y, width, height};
if (cast->current_frame.damage_count < 4) {
cast->current_frame.damage[cast->current_frame.damage_count++] = damage;
} else {
cast->current_frame.damage[3] = merge_damage(&cast->current_frame.damage[3], &damage);
}
}
static void wlr_frame_ready(void *data, struct zwlr_screencopy_frame_v1 *frame, uint32_t tv_sec_hi, uint32_t tv_sec_lo, uint32_t tv_nsec) {
@ -463,10 +467,13 @@ static void hyprland_frame_damage(void *data, struct hyprland_toplevel_export_fr
logprint(TRACE, "hyprland: damage event handler");
cast->current_frame.damage.x = x;
cast->current_frame.damage.y = y;
cast->current_frame.damage.width = width;
cast->current_frame.damage.height = height;
logprint(TRACE, "hyprland: damage %"PRIu32": %"PRIu32",%"PRIu32"x%"PRIu32",%"PRIu32, cast->current_frame.damage_count, x, y, width, height);
struct xdpw_frame_damage damage = {x, y, width, height};
if (cast->current_frame.damage_count < 4) {
cast->current_frame.damage[cast->current_frame.damage_count++] = damage;
} else {
cast->current_frame.damage[3] = merge_damage(&cast->current_frame.damage[3], &damage);
}
}
static void hyprland_frame_ready(void *data, struct hyprland_toplevel_export_frame_v1 *frame, uint32_t tv_sec_hi, uint32_t tv_sec_lo,