mirror of
https://github.com/yshui/picom.git
synced 2024-11-11 13:51:02 -05:00
config: add debug option "consistent_buffer_age"
An attempt to make rendering with damage deterministic even when replayed from a trace. Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This commit is contained in:
parent
5ff88f516e
commit
1bd6cd4be9
3 changed files with 76 additions and 26 deletions
|
@ -523,9 +523,10 @@ const char *vblank_scheduler_str[] = {
|
|||
[LAST_VBLANK_SCHEDULER] = NULL
|
||||
};
|
||||
static const struct debug_options_entry debug_options_entries[] = {
|
||||
{"always_rebind_pixmap", NULL , offsetof(struct debug_options, always_rebind_pixmap)},
|
||||
{"always_rebind_pixmap" , NULL , offsetof(struct debug_options, always_rebind_pixmap)},
|
||||
{"smart_frame_pacing" , NULL , offsetof(struct debug_options, smart_frame_pacing)},
|
||||
{"force_vblank_sched" , vblank_scheduler_str, offsetof(struct debug_options, force_vblank_scheduler)},
|
||||
{"consistent_buffer_age", NULL , offsetof(struct debug_options, consistent_buffer_age)},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
|
|
|
@ -126,6 +126,14 @@ struct debug_options {
|
|||
/// Useful when being traced under apitrace, to force it to pick up
|
||||
/// updated contents. WARNING, extremely slow.
|
||||
int always_rebind_pixmap;
|
||||
/// When using damage, replaying an apitrace becomes non-deterministic, because
|
||||
/// the buffer age we got when we rendered will be different from the buffer age
|
||||
/// apitrace gets when it replays. When this option is enabled, we saves the
|
||||
/// contents of each rendered frame, and at the beginning of each render, we
|
||||
/// restore the content of the back buffer based on the buffer age we get,
|
||||
/// ensuring no matter what buffer age apitrace gets during replay, the result
|
||||
/// will be the same.
|
||||
int consistent_buffer_age;
|
||||
};
|
||||
|
||||
extern struct debug_options global_debug_options;
|
||||
|
|
|
@ -26,6 +26,8 @@ struct renderer {
|
|||
image_handle *monitor_repaint_copy;
|
||||
/// Regions painted over by monitor repaint
|
||||
region_t *monitor_repaint_region;
|
||||
/// Copy of the entire back buffer
|
||||
image_handle *back_buffer_copy;
|
||||
/// Current frame index in ring buffer
|
||||
int frame_index;
|
||||
int max_buffer_age;
|
||||
|
@ -176,6 +178,13 @@ renderer_set_root_size(struct renderer *r, struct backend_base *backend, ivec2 r
|
|||
if (r->back_image) {
|
||||
backend->ops->release_image(backend, r->back_image);
|
||||
}
|
||||
if (r->back_buffer_copy) {
|
||||
for (int i = 0; i < r->max_buffer_age; i++) {
|
||||
backend->ops->release_image(backend, r->back_buffer_copy[i]);
|
||||
}
|
||||
free(r->back_buffer_copy);
|
||||
r->back_buffer_copy = NULL;
|
||||
}
|
||||
if (r->monitor_repaint_copy) {
|
||||
for (int i = 0; i < r->max_buffer_age; i++) {
|
||||
backend->ops->release_image(backend, r->monitor_repaint_copy[i]);
|
||||
|
@ -454,7 +463,9 @@ static bool renderer_prepare_commands(struct renderer *r, struct backend_base *b
|
|||
return true;
|
||||
}
|
||||
|
||||
void renderer_ensure_monitor_repaint_ready(struct renderer *r, struct backend_base *backend) {
|
||||
void renderer_ensure_images_ready(struct renderer *r, struct backend_base *backend,
|
||||
bool monitor_repaint) {
|
||||
if (monitor_repaint) {
|
||||
if (!r->monitor_repaint_pixel) {
|
||||
r->monitor_repaint_pixel = backend->ops->new_image(
|
||||
backend, BACKEND_IMAGE_FORMAT_PIXMAP, (ivec2){1, 1});
|
||||
|
@ -478,6 +489,17 @@ void renderer_ensure_monitor_repaint_ready(struct renderer *r, struct backend_ba
|
|||
pixman_region32_init(&r->monitor_repaint_region[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (global_debug_options.consistent_buffer_age && !r->back_buffer_copy) {
|
||||
r->back_buffer_copy = ccalloc(r->max_buffer_age, image_handle);
|
||||
for (int i = 0; i < r->max_buffer_age; i++) {
|
||||
r->back_buffer_copy[i] = backend->ops->new_image(
|
||||
backend, BACKEND_IMAGE_FORMAT_PIXMAP,
|
||||
(ivec2){.width = r->canvas_size.width,
|
||||
.height = r->canvas_size.height});
|
||||
BUG_ON(!r->back_buffer_copy[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// @return true if a frame is rendered, false if this frame is skipped.
|
||||
|
@ -506,9 +528,7 @@ bool renderer_render(struct renderer *r, struct backend_base *backend,
|
|||
return false;
|
||||
}
|
||||
|
||||
if (monitor_repaint) {
|
||||
renderer_ensure_monitor_repaint_ready(r, backend);
|
||||
}
|
||||
renderer_ensure_images_ready(r, backend, monitor_repaint);
|
||||
|
||||
command_builder_build(cb, layout, force_blend, blur_frame, inactive_dim_fixed,
|
||||
max_brightness, inactive_dim, monitors, wintype_options);
|
||||
|
@ -539,6 +559,16 @@ bool renderer_render(struct renderer *r, struct backend_base *backend,
|
|||
}
|
||||
auto buffer_age =
|
||||
(use_damage || monitor_repaint) ? backend->ops->buffer_age(backend) : 0;
|
||||
if (buffer_age > 0 && global_debug_options.consistent_buffer_age) {
|
||||
int past_frame =
|
||||
(r->frame_index + r->max_buffer_age - buffer_age) % r->max_buffer_age;
|
||||
region_t region;
|
||||
pixman_region32_init_rect(®ion, 0, 0, (unsigned)r->canvas_size.width,
|
||||
(unsigned)r->canvas_size.height);
|
||||
backend->ops->copy_area(backend, (ivec2){}, backend->ops->back_buffer(backend),
|
||||
r->back_buffer_copy[past_frame], ®ion);
|
||||
pixman_region32_fini(®ion);
|
||||
}
|
||||
if (buffer_age > 0 && (unsigned)buffer_age <= layout_manager_max_buffer_age(lm)) {
|
||||
layout_manager_damage(lm, (unsigned)buffer_age, blur_size, &damage_region);
|
||||
}
|
||||
|
@ -604,10 +634,21 @@ bool renderer_render(struct renderer *r, struct backend_base *backend,
|
|||
backend->ops->blit(backend, (ivec2){}, r->back_image, &blit);
|
||||
}
|
||||
|
||||
if (backend->ops->present) {
|
||||
backend->ops->copy_area_quantize(backend, (ivec2){},
|
||||
backend->ops->back_buffer(backend),
|
||||
r->back_image, &damage_region);
|
||||
|
||||
if (global_debug_options.consistent_buffer_age) {
|
||||
region_t region;
|
||||
pixman_region32_init_rect(®ion, 0, 0, (unsigned)r->canvas_size.width,
|
||||
(unsigned)r->canvas_size.height);
|
||||
backend->ops->copy_area(backend, (ivec2){},
|
||||
r->back_buffer_copy[r->frame_index],
|
||||
backend->ops->back_buffer(backend), ®ion);
|
||||
pixman_region32_fini(®ion);
|
||||
}
|
||||
|
||||
if (backend->ops->present) {
|
||||
backend->ops->present(backend);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue