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
|
@ -526,6 +526,7 @@ 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)},
|
{"smart_frame_pacing" , NULL , offsetof(struct debug_options, smart_frame_pacing)},
|
||||||
{"force_vblank_sched" , vblank_scheduler_str, offsetof(struct debug_options, force_vblank_scheduler)},
|
{"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
|
// clang-format on
|
||||||
|
|
||||||
|
|
|
@ -126,6 +126,14 @@ struct debug_options {
|
||||||
/// Useful when being traced under apitrace, to force it to pick up
|
/// Useful when being traced under apitrace, to force it to pick up
|
||||||
/// updated contents. WARNING, extremely slow.
|
/// updated contents. WARNING, extremely slow.
|
||||||
int always_rebind_pixmap;
|
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;
|
extern struct debug_options global_debug_options;
|
||||||
|
|
|
@ -26,6 +26,8 @@ struct renderer {
|
||||||
image_handle *monitor_repaint_copy;
|
image_handle *monitor_repaint_copy;
|
||||||
/// Regions painted over by monitor repaint
|
/// Regions painted over by monitor repaint
|
||||||
region_t *monitor_repaint_region;
|
region_t *monitor_repaint_region;
|
||||||
|
/// Copy of the entire back buffer
|
||||||
|
image_handle *back_buffer_copy;
|
||||||
/// Current frame index in ring buffer
|
/// Current frame index in ring buffer
|
||||||
int frame_index;
|
int frame_index;
|
||||||
int max_buffer_age;
|
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) {
|
if (r->back_image) {
|
||||||
backend->ops->release_image(backend, 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) {
|
if (r->monitor_repaint_copy) {
|
||||||
for (int i = 0; i < r->max_buffer_age; i++) {
|
for (int i = 0; i < r->max_buffer_age; i++) {
|
||||||
backend->ops->release_image(backend, r->monitor_repaint_copy[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;
|
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) {
|
if (!r->monitor_repaint_pixel) {
|
||||||
r->monitor_repaint_pixel = backend->ops->new_image(
|
r->monitor_repaint_pixel = backend->ops->new_image(
|
||||||
backend, BACKEND_IMAGE_FORMAT_PIXMAP, (ivec2){1, 1});
|
backend, BACKEND_IMAGE_FORMAT_PIXMAP, (ivec2){1, 1});
|
||||||
|
@ -479,6 +490,17 @@ void renderer_ensure_monitor_repaint_ready(struct renderer *r, struct backend_ba
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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.
|
/// @return true if a frame is rendered, false if this frame is skipped.
|
||||||
bool renderer_render(struct renderer *r, struct backend_base *backend,
|
bool renderer_render(struct renderer *r, struct backend_base *backend,
|
||||||
|
@ -506,9 +528,7 @@ bool renderer_render(struct renderer *r, struct backend_base *backend,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (monitor_repaint) {
|
renderer_ensure_images_ready(r, backend, monitor_repaint);
|
||||||
renderer_ensure_monitor_repaint_ready(r, backend);
|
|
||||||
}
|
|
||||||
|
|
||||||
command_builder_build(cb, layout, force_blend, blur_frame, inactive_dim_fixed,
|
command_builder_build(cb, layout, force_blend, blur_frame, inactive_dim_fixed,
|
||||||
max_brightness, inactive_dim, monitors, wintype_options);
|
max_brightness, inactive_dim, monitors, wintype_options);
|
||||||
|
@ -539,6 +559,16 @@ bool renderer_render(struct renderer *r, struct backend_base *backend,
|
||||||
}
|
}
|
||||||
auto buffer_age =
|
auto buffer_age =
|
||||||
(use_damage || monitor_repaint) ? backend->ops->buffer_age(backend) : 0;
|
(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)) {
|
if (buffer_age > 0 && (unsigned)buffer_age <= layout_manager_max_buffer_age(lm)) {
|
||||||
layout_manager_damage(lm, (unsigned)buffer_age, blur_size, &damage_region);
|
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);
|
backend->ops->blit(backend, (ivec2){}, r->back_image, &blit);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (backend->ops->present) {
|
|
||||||
backend->ops->copy_area_quantize(backend, (ivec2){},
|
backend->ops->copy_area_quantize(backend, (ivec2){},
|
||||||
backend->ops->back_buffer(backend),
|
backend->ops->back_buffer(backend),
|
||||||
r->back_image, &damage_region);
|
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);
|
backend->ops->present(backend);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue