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:
Simon Ser 2019-10-13 18:28:45 +03:00
parent 76cca57504
commit 5a66e567ec
No known key found for this signature in database
GPG key ID: 0FDE7BE0E88F5E48
3 changed files with 113 additions and 4 deletions

102
display.c
View file

@ -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;
}

View file

@ -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
View file

@ -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;
}
}