Skip to content

Commit

Permalink
New upstream version 0.4.1
Browse files Browse the repository at this point in the history
  • Loading branch information
werdahias committed Jul 14, 2023
1 parent 38efa56 commit 28f8e8d
Show file tree
Hide file tree
Showing 26 changed files with 1,098 additions and 244 deletions.
2 changes: 1 addition & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ trim_trailing_whitespace = true
insert_final_newline = true
indent_style = tab
indent_size = 8
max_line_length = 80
max_line_length = 100
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,16 @@ Lightweight KMS plane library.

libliftoff eases the use of KMS planes from userspace without standing in your
way. Users create "virtual planes" called layers, set KMS properties on them,
and libliftoff will pick planes for these layers if possible.
and libliftoff will pick hardware planes for these layers if possible.

Resources:

* [Blog post introducing the project][intro-post]
* [FOSDEM 2020 talk][fosdem-2020]

libliftoff is used in production by [gamescope] on Steam Deck devices, and work
is underway to integrate it with [wlroots].

## Building

Depends on libdrm. Requires universal planes and atomic.
Expand Down Expand Up @@ -76,3 +79,5 @@ MIT
[fosdem-2020]: https://fosdem.org/2020/schedule/event/kms_planes/
[gitlab]: https://gitlab.freedesktop.org/emersion/libliftoff
[weston-contributing]: https://gitlab.freedesktop.org/wayland/weston/-/blob/master/CONTRIBUTING.md
[gamescope]: https://github.com/Plagman/gamescope
[wlroots]: https://gitlab.freedesktop.org/wlroots/wlroots
91 changes: 81 additions & 10 deletions alloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,7 @@ output_choose_layers(struct liftoff_output *output, struct alloc_result *result,
step->log_prefix, plane->id, step->plane_idx + 1, result->planes_len);

liftoff_list_for_each(layer, &output->layers, link) {
if (layer->plane != NULL || layer->force_composition) {
if (layer->plane != NULL) {
continue;
}
if (!layer_is_visible(layer)) {
Expand All @@ -461,6 +461,18 @@ output_choose_layers(struct liftoff_output *output, struct alloc_result *result,
return ret;
}

layer_add_candidate_plane(layer, plane);

/* If composition is forced, wait until after the
* layer_add_candidate_plane() call to reject the plane: we want
* to return a meaningful list of candidate planes so that the
* API user has the opportunity to re-allocate its buffers with
* scanout-capable ones. Same deal for the FB check. */
if (layer->force_composition || !plane_check_layer_fb(plane, layer)) {
drmModeAtomicSetCursor(result->req, cursor);
continue;
}

ret = device_test_commit(device, result->req, result->flags);
if (ret == 0) {
liftoff_log(LIFTOFF_DEBUG,
Expand Down Expand Up @@ -507,7 +519,6 @@ apply_current(struct liftoff_device *device, drmModeAtomicReq *req)

liftoff_list_for_each(plane, &device->planes, link) {
ret = plane_apply(plane, plane->layer, req);
assert(ret != -EINVAL);
if (ret != 0) {
drmModeAtomicSetCursor(req, cursor);
return ret;
Expand All @@ -517,33 +528,65 @@ apply_current(struct liftoff_device *device, drmModeAtomicReq *req)
return 0;
}

static bool
fb_info_needs_realloc(const drmModeFB2 *a, const drmModeFB2 *b)
{
if (a->width != b->width || a->height != b->height ||
a->pixel_format != b->pixel_format || a->modifier != b->modifier) {
return true;
}

/* TODO: consider checking pitch and offset? */

return false;
}

static bool
layer_needs_realloc(struct liftoff_layer *layer)
{
size_t i;
struct liftoff_layer_property *prop;

if (layer->changed) {
liftoff_log(LIFTOFF_DEBUG, "Cannot re-use previous allocation: "
"layer property added or force composition changed");
return true;
}

for (i = 0; i < layer->props_len; i++) {
prop = &layer->props[i];
if (prop->value == prop->prev_value) {
continue;
}

/* If FB_ID changes from non-zero to zero, we don't need to
* display this layer anymore, so we may be able to re-use its
* plane for another layer. If FB_ID changes from zero to
* non-zero, we might be able to find a plane for this layer.
* If FB_ID changes from non-zero to non-zero, we can try to
* re-use the previous allocation. */
* If FB_ID changes from non-zero to non-zero and the FB
* attributes didn't change, we can try to re-use the previous
* allocation. */
if (strcmp(prop->name, "FB_ID") == 0) {
if (prop->value == 0 && prop->prev_value == 0) {
continue;
}

if (prop->value == 0 || prop->prev_value == 0) {
liftoff_log(LIFTOFF_DEBUG, "Cannot re-use previous allocation: "
"layer enabled or disabled");
return true;
}
/* TODO: check format/modifier is the same? */

if (fb_info_needs_realloc(&layer->fb_info,
&layer->prev_fb_info)) {
liftoff_log(LIFTOFF_DEBUG, "Cannot re-use previous allocation: "
"FB info changed");
return true;
}

continue;
}

/* For all properties except FB_ID, we can skip realloc if the
* value didn't change. */
if (prop->value == prop->prev_value) {
continue;
}

Expand All @@ -553,6 +596,8 @@ layer_needs_realloc(struct liftoff_layer *layer)
if (strcmp(prop->name, "alpha") == 0) {
if (prop->value == 0 || prop->prev_value == 0 ||
prop->value == 0xFFFF || prop->prev_value == 0xFFFF) {
liftoff_log(LIFTOFF_DEBUG, "Cannot re-use previous allocation: "
"alpha changed");
return true;
}
continue;
Expand All @@ -567,6 +612,8 @@ layer_needs_realloc(struct liftoff_layer *layer)

/* TODO: if CRTC_{X,Y,W,H} changed but intersection with other
* layers hasn't changed, don't realloc */
liftoff_log(LIFTOFF_DEBUG, "Cannot re-use previous allocation: "
"property \"%s\" changed", prop->name);
return true;
}

Expand All @@ -584,6 +631,8 @@ reuse_previous_alloc(struct liftoff_output *output, drmModeAtomicReq *req,
device = output->device;

if (output->layers_changed) {
liftoff_log(LIFTOFF_DEBUG, "Cannot re-use previous allocation: "
"a layer has been added or removed");
return -EINVAL;
}

Expand Down Expand Up @@ -624,10 +673,10 @@ update_layers_priority(struct liftoff_device *device)
{
struct liftoff_output *output;
struct liftoff_layer *layer;
bool period_elapsed;

device->page_flip_counter++;
bool period_elapsed =
device->page_flip_counter >= LIFTOFF_PRIORITY_PERIOD;
period_elapsed = device->page_flip_counter >= LIFTOFF_PRIORITY_PERIOD;
if (period_elapsed) {
device->page_flip_counter = 0;
}
Expand All @@ -639,6 +688,22 @@ update_layers_priority(struct liftoff_device *device)
}
}

static void
update_layers_fb_info(struct liftoff_output *output)
{
struct liftoff_layer *layer;

/* We don't know what the library user did in-between
* liftoff_output_apply() calls. They might've removed the FB and
* re-created a completely different one which happens to have the same
* FB ID. */
liftoff_list_for_each(layer, &output->layers, link) {
memset(&layer->fb_info, 0, sizeof(layer->fb_info));
layer_cache_fb_info(layer);
/* TODO: propagate error? */
}
}

static void
log_reuse(struct liftoff_output *output)
{
Expand Down Expand Up @@ -697,6 +762,7 @@ liftoff_output_apply(struct liftoff_output *output, drmModeAtomicReq *req,
device = output->device;

update_layers_priority(device);
update_layers_fb_info(output);

ret = reuse_previous_alloc(output, req, flags);
if (ret == 0) {
Expand All @@ -705,6 +771,11 @@ liftoff_output_apply(struct liftoff_output *output, drmModeAtomicReq *req,
}
log_no_reuse(output);

/* Reset layers' candidate planes */
liftoff_list_for_each(layer, &output->layers, link) {
layer_reset_candidate_planes(layer);
}

device->test_commit_counter = 0;
output_log_layers(output);

Expand Down
19 changes: 14 additions & 5 deletions device.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ liftoff_device_create(int drm_fd)
{
struct liftoff_device *device;
drmModeRes *drm_res;
drmModePlaneRes *drm_plane_res;

device = calloc(1, sizeof(*device));
if (device == NULL) {
Expand All @@ -34,19 +35,27 @@ liftoff_device_create(int drm_fd)
return NULL;
}

device->crtcs = malloc(drm_res->count_crtcs * sizeof(uint32_t));
device->crtcs_len = (size_t)drm_res->count_crtcs;
device->crtcs = malloc(device->crtcs_len * sizeof(device->crtcs[0]));
if (device->crtcs == NULL) {
liftoff_log_errno(LIFTOFF_ERROR, "malloc");
drmModeFreeResources(drm_res);
liftoff_device_destroy(device);
return NULL;
}
device->crtcs_len = drm_res->count_crtcs;
memcpy(device->crtcs, drm_res->crtcs,
drm_res->count_crtcs * sizeof(uint32_t));
memcpy(device->crtcs, drm_res->crtcs, device->crtcs_len * sizeof(device->crtcs[0]));

drmModeFreeResources(drm_res);

drm_plane_res = drmModeGetPlaneResources(device->drm_fd);
if (drm_plane_res == NULL) {
liftoff_log_errno(LIFTOFF_ERROR, "drmModeGetPlaneResources");
liftoff_device_destroy(device);
return NULL;
}
device->planes_cap = drm_plane_res->count_planes;
drmModeFreePlaneResources(drm_plane_res);

return device;
}

Expand Down Expand Up @@ -97,7 +106,7 @@ device_test_commit(struct liftoff_device *device, drmModeAtomicReq *req,

device->test_commit_counter++;

flags &= ~DRM_MODE_PAGE_FLIP_EVENT;
flags &= ~(uint32_t)DRM_MODE_PAGE_FLIP_EVENT;
do {
ret = drmModeAtomicCommit(device->drm_fd, req,
DRM_MODE_ATOMIC_TEST_ONLY | flags,
Expand Down
13 changes: 8 additions & 5 deletions example/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,14 @@ dumb_fb_init(struct dumb_fb *fb, int drm_fd, uint32_t format, uint32_t width,
{
int ret;
uint32_t fb_id;
struct drm_mode_create_dumb create;
uint32_t handles[4] = {0};
uint32_t strides[4] = {0};
uint32_t offsets[4] = { 0 };

assert(format == DRM_FORMAT_ARGB8888 || format == DRM_FORMAT_XRGB8888);

struct drm_mode_create_dumb create = {
create = (struct drm_mode_create_dumb) {
.width = width,
.height = height,
.bpp = 32,
Expand All @@ -101,9 +105,8 @@ dumb_fb_init(struct dumb_fb *fb, int drm_fd, uint32_t format, uint32_t width,
return false;
}

uint32_t handles[4] = { create.handle };
uint32_t strides[4] = { create.pitch };
uint32_t offsets[4] = { 0 };
handles[0] = create.handle;
strides[0] = create.pitch;
ret = drmModeAddFB2(drm_fd, width, height, format, handles, strides,
offsets, &fb_id, 0);
if (ret < 0) {
Expand Down Expand Up @@ -131,7 +134,7 @@ dumb_fb_map(struct dumb_fb *fb, int drm_fd)
}

return mmap(0, fb->size, PROT_READ | PROT_WRITE, MAP_SHARED, drm_fd,
map.offset);
(off_t)map.offset);
}

void
Expand Down
26 changes: 13 additions & 13 deletions example/compositor.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ static const uint32_t colors[] = {
};

static struct liftoff_layer *
add_layer(int drm_fd, struct liftoff_output *output, int x, int y, int width,
int height, bool with_alpha, bool white, struct dumb_fb *fb)
add_layer(int drm_fd, struct liftoff_output *output, int x, int y, uint32_t width,
uint32_t height, bool with_alpha, bool white, struct dumb_fb *fb)
{
static size_t color_idx = 0;
uint32_t color;
Expand All @@ -51,8 +51,8 @@ add_layer(int drm_fd, struct liftoff_output *output, int x, int y, int width,

layer = liftoff_layer_create(output);
liftoff_layer_set_property(layer, "FB_ID", fb->id);
liftoff_layer_set_property(layer, "CRTC_X", x);
liftoff_layer_set_property(layer, "CRTC_Y", y);
liftoff_layer_set_property(layer, "CRTC_X", (uint64_t)x);
liftoff_layer_set_property(layer, "CRTC_Y", (uint64_t)y);
liftoff_layer_set_property(layer, "CRTC_W", width);
liftoff_layer_set_property(layer, "CRTC_H", height);
liftoff_layer_set_property(layer, "SRC_X", 0);
Expand All @@ -74,23 +74,23 @@ composite(int drm_fd, struct dumb_fb *dst_fb, struct dumb_fb *src_fb, int dst_x,
dst = dumb_fb_map(dst_fb, drm_fd);
src = dumb_fb_map(src_fb, drm_fd);

src_width = src_fb->width;
src_width = (int)src_fb->width;
if (dst_x < 0) {
dst_x = 0;
}
if (dst_x + src_width > (int)dst_fb->width) {
src_width = dst_fb->width - dst_x;
src_width = (int)dst_fb->width - dst_x;
}

for (i = 0; i < (int)src_fb->height; i++) {
y = dst_y + i;
if (y < 0 || y >= (int)dst_fb->height) {
continue;
}
memcpy(dst + dst_fb->stride * y +
dst_x * sizeof(uint32_t),
src + src_fb->stride * i,
src_width * sizeof(uint32_t));
memcpy(dst + dst_fb->stride * (size_t)y +
(size_t)dst_x * sizeof(uint32_t),
src + src_fb->stride * (size_t)i,
(size_t)src_width * sizeof(uint32_t));
}

munmap(dst, dst_fb->size);
Expand Down Expand Up @@ -122,7 +122,7 @@ main(int argc, char *argv[])
while ((opt = getopt(argc, argv, "l:h")) != -1) {
switch (opt) {
case 'l':
layers_len = atoi(optarg);
layers_len = (size_t)atoi(optarg);
break;
default:
fprintf(stderr,
Expand Down Expand Up @@ -182,7 +182,7 @@ main(int argc, char *argv[])
layers[0] = add_layer(drm_fd, output, 0, 0, crtc->mode.hdisplay,
crtc->mode.vdisplay, false, true, &fbs[0]);
for (i = 1; i < layers_len; i++) {
layers[i] = add_layer(drm_fd, output, 100 * i, 100 * i,
layers[i] = add_layer(drm_fd, output, 100 * (int)i, 100 * (int)i,
256, 256, i % 2, false, &fbs[i]);
}

Expand All @@ -205,7 +205,7 @@ main(int argc, char *argv[])
for (i = 1; i < layers_len; i++) {
if (liftoff_layer_needs_composition(layers[i])) {
composite(drm_fd, &composition_fb, &fbs[i],
i * 100, i * 100);
(int)i * 100, (int)i * 100);
}
}

Expand Down
Loading

0 comments on commit 28f8e8d

Please sign in to comment.