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;
|
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)
|
bool liftoff_display_apply(struct liftoff_display *display, drmModeAtomicReq *req)
|
||||||
{
|
{
|
||||||
struct liftoff_output *output;
|
struct liftoff_output *output;
|
||||||
|
@ -617,6 +704,11 @@ bool liftoff_display_apply(struct liftoff_display *display, drmModeAtomicReq *re
|
||||||
size_t i;
|
size_t i;
|
||||||
bool compatible;
|
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.
|
/* Unset all existing plane and layer mappings.
|
||||||
TODO: incremental updates keeping old configuration if possible */
|
TODO: incremental updates keeping old configuration if possible */
|
||||||
liftoff_list_for_each(plane, &display->planes, link) {
|
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,
|
liftoff_log(LIFTOFF_DEBUG,
|
||||||
"Assigning layer %p to plane %"PRIu32,
|
"Assigning layer %p to plane %"PRIu32,
|
||||||
(void *)layer, plane->id);
|
(void *)layer, plane->id);
|
||||||
if (!plane_apply(plane, layer, req, &compatible)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
assert(compatible);
|
|
||||||
|
|
||||||
assert(plane->layer == NULL);
|
assert(plane->layer == NULL);
|
||||||
assert(layer->plane == NULL);
|
assert(layer->plane == NULL);
|
||||||
plane->layer = layer;
|
plane->layer = layer;
|
||||||
layer->plane = plane;
|
layer->plane = plane;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!apply_current(display, req)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
free(step.alloc);
|
free(step.alloc);
|
||||||
free(result.best);
|
free(result.best);
|
||||||
|
|
||||||
|
mark_layers_clean(display);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,7 @@ struct liftoff_layer {
|
||||||
struct liftoff_layer_property {
|
struct liftoff_layer_property {
|
||||||
char name[DRM_PROP_NAME_LEN];
|
char name[DRM_PROP_NAME_LEN];
|
||||||
uint64_t value;
|
uint64_t value;
|
||||||
|
bool changed;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct liftoff_plane {
|
struct liftoff_plane {
|
||||||
|
@ -69,6 +70,7 @@ struct liftoff_layer_property *layer_get_property(struct liftoff_layer *layer,
|
||||||
const char *name);
|
const char *name);
|
||||||
void layer_get_rect(struct liftoff_layer *layer, struct liftoff_rect *rect);
|
void layer_get_rect(struct liftoff_layer *layer, struct liftoff_rect *rect);
|
||||||
bool layer_intersects(struct liftoff_layer *a, struct liftoff_layer *b);
|
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);
|
struct liftoff_plane *plane_create(struct liftoff_display *display, uint32_t id);
|
||||||
void plane_destroy(struct liftoff_plane *plane);
|
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];
|
prop = &layer->props[layer->props_len - 1];
|
||||||
memset(prop, 0, sizeof(*prop));
|
memset(prop, 0, sizeof(*prop));
|
||||||
strncpy(prop->name, name, sizeof(prop->name) - 1);
|
strncpy(prop->name, name, sizeof(prop->name) - 1);
|
||||||
|
|
||||||
|
prop->changed = true;
|
||||||
|
} else {
|
||||||
|
prop->changed = prop->value != value;
|
||||||
}
|
}
|
||||||
|
|
||||||
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 &&
|
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;
|
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