From 29dfe66ecfad64ba0fb2c4d58f0d2cdcef838aa6 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 14 Oct 2019 14:37:19 +0300 Subject: [PATCH] example: add dynamic example This example demonstrates how incremental layer updates should be applied. It contains a basic rendering loop. Each layers has a back-buffer and a front-buffer. The color of one of the layers will change at each frame. --- example/dynamic.c | 230 ++++++++++++++++++++++++++++++++++++++++++++ example/meson.build | 6 ++ 2 files changed, 236 insertions(+) create mode 100644 example/dynamic.c diff --git a/example/dynamic.c b/example/dynamic.c new file mode 100644 index 0000000..c35f30f --- /dev/null +++ b/example/dynamic.c @@ -0,0 +1,230 @@ +/* Dynamic: create a few layers, setup a rendering loop for one of them. The + * result is a rectangle updating its color while all other layers that make it + * into a plane are static. */ + +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "common.h" + +#define LAYERS_LEN 4 + +struct example_layer { + float color[3]; + int dec; + int x, y; + + struct dumb_fb fbs[2]; + size_t front_fb; + + struct liftoff_layer *layer; +}; + +static int drm_fd = -1; +static struct liftoff_display *display = NULL; +static struct example_layer layers[LAYERS_LEN] = {0}; +static size_t active_layer_idx = 2; + +static bool init_layer(int drm_fd, struct example_layer *layer, + struct liftoff_output *output, int width, int height, + bool with_alpha) +{ + static size_t color_idx = 0; + static float color_value = 1.0; + uint32_t format; + + format = with_alpha ? DRM_FORMAT_ARGB8888 : DRM_FORMAT_XRGB8888; + if (!dumb_fb_init(&layer->fbs[0], drm_fd, format, width, height) || + !dumb_fb_init(&layer->fbs[1], drm_fd, format, width, height)) { + fprintf(stderr, "failed to create framebuffer\n"); + return false; + } + + layer->layer = liftoff_layer_create(output); + liftoff_layer_set_property(layer->layer, "CRTC_W", width); + liftoff_layer_set_property(layer->layer, "CRTC_H", height); + liftoff_layer_set_property(layer->layer, "SRC_X", 0); + liftoff_layer_set_property(layer->layer, "SRC_Y", 0); + liftoff_layer_set_property(layer->layer, "SRC_W", width << 16); + liftoff_layer_set_property(layer->layer, "SRC_H", height << 16); + + layer->color[color_idx % 3] = color_value; + color_idx++; + if (color_idx % 3 == 0) { + color_value -= 0.1; + } + + return true; +} + +static void draw_layer(int drm_fd, struct example_layer *layer) +{ + uint32_t color; + struct dumb_fb *fb; + + layer->front_fb = (layer->front_fb + 1) % 2; + fb = &layer->fbs[layer->front_fb]; + + color = ((uint32_t)0xFF << 24) | + ((uint32_t)(layer->color[0] * 0xFF) << 16) | + ((uint32_t)(layer->color[1] * 0xFF) << 8) | + (uint32_t)(layer->color[2] * 0xFF); + + dumb_fb_fill(fb, drm_fd, color); + + liftoff_layer_set_property(layer->layer, "FB_ID", fb->id); + liftoff_layer_set_property(layer->layer, "CRTC_X", layer->x); + liftoff_layer_set_property(layer->layer, "CRTC_Y", layer->y); +} + +static bool draw(void) +{ + struct example_layer *active_layer; + drmModeAtomicReq *req; + int ret, inc; + size_t i; + + active_layer = &layers[active_layer_idx]; + + inc = (active_layer->dec + 1) % 3; + + active_layer->color[inc] += 0.05; + active_layer->color[active_layer->dec] -= 0.05; + + if (active_layer->color[active_layer->dec] < 0.0f) { + active_layer->color[inc] = 1.0f; + active_layer->color[active_layer->dec] = 0.0f; + active_layer->dec = inc; + } + + draw_layer(drm_fd, active_layer); + + req = drmModeAtomicAlloc(); + if (!liftoff_display_apply(display, req)) { + perror("liftoff_display_commit"); + return false; + } + + ret = drmModeAtomicCommit(drm_fd, req, DRM_MODE_ATOMIC_NONBLOCK | + DRM_MODE_PAGE_FLIP_EVENT, NULL); + if (ret < 0) { + perror("drmModeAtomicCommit"); + return false; + } + + drmModeAtomicFree(req); + + for (i = 0; i < sizeof(layers) / sizeof(layers[0]); i++) { + printf("Layer %zu got assigned to plane %u\n", i, + liftoff_layer_get_plane_id(layers[i].layer)); + } + + return true; +} + +static void page_flip_handler(int fd, unsigned seq, unsigned tv_sec, + unsigned tv_usec, unsigned crtc_id, void *data) +{ + draw(); +} + +int main(int argc, char *argv[]) +{ + drmModeRes *drm_res; + drmModeCrtc *crtc; + drmModeConnector *connector; + struct liftoff_output *output; + size_t i; + int ret; + + drm_fd = open("/dev/dri/card0", O_RDWR | O_CLOEXEC); + if (drm_fd < 0) { + perror("open"); + return 1; + } + + if (drmSetClientCap(drm_fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1) < 0) { + perror("drmSetClientCap(UNIVERSAL_PLANES)"); + return 1; + } + if (drmSetClientCap(drm_fd, DRM_CLIENT_CAP_ATOMIC, 1) < 0) { + perror("drmSetClientCap(ATOMIC)"); + return 1; + } + + display = liftoff_display_create(drm_fd); + if (display == NULL) { + perror("liftoff_display_create"); + return 1; + } + + drm_res = drmModeGetResources(drm_fd); + connector = pick_connector(drm_fd, drm_res); + crtc = pick_crtc(drm_fd, drm_res, connector); + disable_all_crtcs_except(drm_fd, drm_res, crtc->crtc_id); + output = liftoff_output_create(display, crtc->crtc_id); + drmModeFreeResources(drm_res); + + if (connector == NULL) { + fprintf(stderr, "no connector found\n"); + return 1; + } + if (crtc == NULL || !crtc->mode_valid) { + fprintf(stderr, "no CRTC found\n"); + return 1; + } + + printf("Using connector %d, CRTC %d\n", connector->connector_id, + crtc->crtc_id); + + init_layer(drm_fd, &layers[0], output, crtc->mode.hdisplay, + crtc->mode.vdisplay, false); + for (i = 1; i < LAYERS_LEN; i++) { + init_layer(drm_fd, &layers[i], output, 100, 100, i % 2); + layers[i].x = 100 * i; + layers[i].y = 100 * i; + } + + for (i = 0; i < LAYERS_LEN; i++) { + liftoff_layer_set_property(layers[i].layer, "zpos", i); + + draw_layer(drm_fd, &layers[i]); + } + + draw(); + + for (i = 0; i < 120; i++) { + drmEventContext drm_event = { + .version = 3, + .page_flip_handler2 = page_flip_handler, + }; + struct pollfd pfd = { + .fd = drm_fd, + .events = POLLIN, + }; + + ret = poll(&pfd, 1, 1000); + if (ret != 1) { + perror("poll"); + return 1; + } + + drmHandleEvent(drm_fd, &drm_event); + } + + for (i = 0; i < sizeof(layers) / sizeof(layers[0]); i++) { + liftoff_layer_destroy(layers[i].layer); + } + liftoff_output_destroy(output); + drmModeFreeCrtc(crtc); + drmModeFreeConnector(connector); + liftoff_display_destroy(display); + return 0; +} diff --git a/example/meson.build b/example/meson.build index 9aace38..9d847cb 100644 --- a/example/meson.build +++ b/example/meson.build @@ -9,3 +9,9 @@ executable( files('common.c', 'compositor.c'), dependencies: [liftoff], ) + +executable( + 'dynamic', + files('common.c', 'dynamic.c'), + dependencies: [liftoff], +)