Skip to content

Commit

Permalink
screencast: send damage via PipeWire
Browse files Browse the repository at this point in the history
We can export buffer damage information via PipeWire to enable clients
to redraw only the damaged parts.
  • Loading branch information
columbarius committed Feb 20, 2023
1 parent 1dfee26 commit 1a344b7
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 8 deletions.
5 changes: 4 additions & 1 deletion include/screencast_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,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;
};
Expand Down Expand Up @@ -216,4 +217,6 @@ enum spa_video_format xdpw_format_pw_strip_alpha(enum spa_video_format format);

enum xdpw_chooser_types get_chooser_type(const char *chooser_type);
const char *chooser_type_str(enum xdpw_chooser_types chooser_type);

struct xdpw_frame_damage merge_damage(struct xdpw_frame_damage *damage1, struct xdpw_frame_damage *damage2);
#endif /* SCREENCAST_COMMON_H */
46 changes: 43 additions & 3 deletions src/screencast/pipewire_screencast.c
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ static void pwr_handle_stream_param_changed(void *data, uint32_t id,
struct pw_stream *stream = cast->stream;
uint8_t params_buffer[3][1024];
struct spa_pod_dynamic_builder b[3];
const struct spa_pod *params[3];
const struct spa_pod *params[4];
uint32_t blocks;
uint32_t data_type;

Expand Down Expand Up @@ -317,12 +317,20 @@ static void pwr_handle_stream_param_changed(void *data, uint32_t id,
SPA_PARAM_META_type, SPA_POD_Id(SPA_META_Header),
SPA_PARAM_META_size, SPA_POD_Int(sizeof(struct spa_meta_header)));

params[2] = spa_pod_builder_add_object(&b[2].b,
params[2] = spa_pod_builder_add_object(&b[1].b,
SPA_TYPE_OBJECT_ParamMeta, SPA_PARAM_Meta,
SPA_PARAM_META_type, SPA_POD_Id(SPA_META_VideoTransform),
SPA_PARAM_META_size, SPA_POD_Int(sizeof(struct spa_meta_videotransform)));

pw_stream_update_params(stream, params, 3);
params[3] = 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, 4);
spa_pod_dynamic_builder_clean(&b[0]);
spa_pod_dynamic_builder_clean(&b[1]);
spa_pod_dynamic_builder_clean(&b[2]);
Expand Down Expand Up @@ -451,6 +459,38 @@ void xdpw_pwr_enqueue_buffer(struct xdpw_screencast_instance *cast) {
logprint(TRACE, "pipewire: transformation %u", vt->transform);
}

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;
Expand Down
14 changes: 14 additions & 0 deletions src/screencast/screencast_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
12 changes: 8 additions & 4 deletions src/screencast/wlr_screencast.c
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ static void wlr_frame_buffer_done(void *data,
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");

Expand All @@ -199,10 +200,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,
Expand Down

0 comments on commit 1a344b7

Please sign in to comment.