mirror of
https://gitlab.freedesktop.org/emersion/libliftoff.git
synced 2025-01-18 10:27:00 +01:00
Track layer property changes
This commit adds basic per-property change tracking. When only FB_ID has changed, we try to re-use the previous allocation. If that fails, go on with regular plane allocation. Closes: https://github.com/emersion/libliftoff/issues/6
This commit is contained in:
parent
76cca57504
commit
5a66e567ec
3 changed files with 113 additions and 4 deletions
102
display.c
102
display.c
|
@ -607,6 +607,93 @@ skip:
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool apply_current(struct liftoff_display *display,
|
||||
drmModeAtomicReq *req)
|
||||
{
|
||||
struct liftoff_plane *plane;
|
||||
int cursor;
|
||||
bool compatible;
|
||||
|
||||
cursor = drmModeAtomicGetCursor(req);
|
||||
|
||||
liftoff_list_for_each(plane, &display->planes, link) {
|
||||
if (!plane_apply(plane, plane->layer, req, &compatible)) {
|
||||
drmModeAtomicSetCursor(req, cursor);
|
||||
return false;
|
||||
}
|
||||
assert(compatible);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool layer_needs_realloc(struct liftoff_layer *layer)
|
||||
{
|
||||
size_t i;
|
||||
struct liftoff_layer_property *prop;
|
||||
|
||||
for (i = 0; i < layer->props_len; i++) {
|
||||
prop = &layer->props[i];
|
||||
if (!prop->changed) {
|
||||
continue;
|
||||
}
|
||||
if (strcmp(prop->name, "FB_ID") == 0) {
|
||||
/* TODO: check format/modifier is the same. Check
|
||||
* previous/next value isn't zero. */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* TODO: if CRTC_{X,Y,W,H} changed but intersection with other
|
||||
* layers hasn't changed, don't realloc */
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool reuse_previous_alloc(struct liftoff_display *display,
|
||||
drmModeAtomicReq *req)
|
||||
{
|
||||
struct liftoff_output *output;
|
||||
struct liftoff_layer *layer;
|
||||
int cursor, ret;
|
||||
|
||||
liftoff_list_for_each(output, &display->outputs, link) {
|
||||
liftoff_list_for_each(layer, &output->layers, link) {
|
||||
if (layer_needs_realloc(layer)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cursor = drmModeAtomicGetCursor(req);
|
||||
|
||||
if (!apply_current(display, req)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ret = drmModeAtomicCommit(display->drm_fd, req,
|
||||
DRM_MODE_ATOMIC_TEST_ONLY, NULL);
|
||||
if (ret != 0) {
|
||||
drmModeAtomicSetCursor(req, cursor);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void mark_layers_clean(struct liftoff_display *display)
|
||||
{
|
||||
struct liftoff_output *output;
|
||||
struct liftoff_layer *layer;
|
||||
|
||||
liftoff_list_for_each(output, &display->outputs, link) {
|
||||
liftoff_list_for_each(layer, &output->layers, link) {
|
||||
layer_mark_clean(layer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool liftoff_display_apply(struct liftoff_display *display, drmModeAtomicReq *req)
|
||||
{
|
||||
struct liftoff_output *output;
|
||||
|
@ -617,6 +704,11 @@ bool liftoff_display_apply(struct liftoff_display *display, drmModeAtomicReq *re
|
|||
size_t i;
|
||||
bool compatible;
|
||||
|
||||
if (reuse_previous_alloc(display, req)) {
|
||||
liftoff_log(LIFTOFF_DEBUG, "Re-using previous plane allocation");
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Unset all existing plane and layer mappings.
|
||||
TODO: incremental updates keeping old configuration if possible */
|
||||
liftoff_list_for_each(plane, &display->planes, link) {
|
||||
|
@ -693,20 +785,22 @@ bool liftoff_display_apply(struct liftoff_display *display, drmModeAtomicReq *re
|
|||
liftoff_log(LIFTOFF_DEBUG,
|
||||
"Assigning layer %p to plane %"PRIu32,
|
||||
(void *)layer, plane->id);
|
||||
if (!plane_apply(plane, layer, req, &compatible)) {
|
||||
return false;
|
||||
}
|
||||
assert(compatible);
|
||||
|
||||
assert(plane->layer == NULL);
|
||||
assert(layer->plane == NULL);
|
||||
plane->layer = layer;
|
||||
layer->plane = plane;
|
||||
}
|
||||
|
||||
if (!apply_current(display, req)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
free(step.alloc);
|
||||
free(result.best);
|
||||
|
||||
mark_layers_clean(display);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ struct liftoff_layer {
|
|||
struct liftoff_layer_property {
|
||||
char name[DRM_PROP_NAME_LEN];
|
||||
uint64_t value;
|
||||
bool changed;
|
||||
};
|
||||
|
||||
struct liftoff_plane {
|
||||
|
@ -69,6 +70,7 @@ struct liftoff_layer_property *layer_get_property(struct liftoff_layer *layer,
|
|||
const char *name);
|
||||
void layer_get_rect(struct liftoff_layer *layer, struct liftoff_rect *rect);
|
||||
bool layer_intersects(struct liftoff_layer *a, struct liftoff_layer *b);
|
||||
void layer_mark_clean(struct liftoff_layer *layer);
|
||||
|
||||
struct liftoff_plane *plane_create(struct liftoff_display *display, uint32_t id);
|
||||
void plane_destroy(struct liftoff_plane *plane);
|
||||
|
|
13
layer.c
13
layer.c
|
@ -66,6 +66,10 @@ void liftoff_layer_set_property(struct liftoff_layer *layer, const char *name,
|
|||
prop = &layer->props[layer->props_len - 1];
|
||||
memset(prop, 0, sizeof(*prop));
|
||||
strncpy(prop->name, name, sizeof(prop->name) - 1);
|
||||
|
||||
prop->changed = true;
|
||||
} else {
|
||||
prop->changed = prop->value != value;
|
||||
}
|
||||
|
||||
prop->value = value;
|
||||
|
@ -104,3 +108,12 @@ bool layer_intersects(struct liftoff_layer *a, struct liftoff_layer *b)
|
|||
return ra.x < rb.x + rb.width && ra.y < rb.y + rb.height &&
|
||||
ra.x + ra.width > rb.x && ra.y + ra.height > rb.y;
|
||||
}
|
||||
|
||||
void layer_mark_clean(struct liftoff_layer *layer)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < layer->props_len; i++) {
|
||||
layer->props[i].changed = false;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue