summaryrefslogtreecommitdiffstats
path: root/meta-agl-drm-lease/recipes-core/psplash/files/0015-psplash-drm.c-Implement-double-buffering.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta-agl-drm-lease/recipes-core/psplash/files/0015-psplash-drm.c-Implement-double-buffering.patch')
-rw-r--r--meta-agl-drm-lease/recipes-core/psplash/files/0015-psplash-drm.c-Implement-double-buffering.patch350
1 files changed, 350 insertions, 0 deletions
diff --git a/meta-agl-drm-lease/recipes-core/psplash/files/0015-psplash-drm.c-Implement-double-buffering.patch b/meta-agl-drm-lease/recipes-core/psplash/files/0015-psplash-drm.c-Implement-double-buffering.patch
new file mode 100644
index 00000000..cd65c990
--- /dev/null
+++ b/meta-agl-drm-lease/recipes-core/psplash/files/0015-psplash-drm.c-Implement-double-buffering.patch
@@ -0,0 +1,350 @@
+From 266b4808094ae636a64e545f5e59fb612827e0ee Mon Sep 17 00:00:00 2001
+From: Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com>
+Date: Mon, 25 Apr 2022 10:59:54 +0300
+Subject: [PATCH 15/17] psplash-drm.c: Implement double buffering
+
+Based on
+https://github.com/dvdhrm/docs/blob/master/drm-howto/modeset-double-buffered.c
+
+drm-backend backport from:
+https://patchwork.yoctoproject.org/project/yocto/cover/20220425075954.10427-1-vasyl.vavrychuk@opensynergy.com/
+
+Signed-off-by: Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com>
+---
+ psplash-drm.c | 176 +++++++++++++++++++++++++++++++++++++++-----------
+ 1 file changed, 140 insertions(+), 36 deletions(-)
+
+diff --git a/psplash-drm.c b/psplash-drm.c
+index 5e56286..fcb7507 100644
+--- a/psplash-drm.c
++++ b/psplash-drm.c
+@@ -29,6 +29,7 @@
+ #include <errno.h>
+ #include <fcntl.h>
+ #include <stdint.h>
++#include <inttypes.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+@@ -41,10 +42,12 @@
+
+ #define MIN(a,b) ((a) < (b) ? (a) : (b))
+
++struct modeset_buf;
+ struct modeset_dev;
+ static int modeset_find_crtc(int fd, drmModeRes *res, drmModeConnector *conn,
+ struct modeset_dev *dev);
+-static int modeset_create_fb(int fd, struct modeset_dev *dev);
++static int modeset_create_fb(int fd, struct modeset_buf *buf);
++static void modeset_destroy_fb(int fd, struct modeset_buf *buf);
+ static int modeset_setup_dev(int fd, drmModeRes *res, drmModeConnector *conn,
+ struct modeset_dev *dev);
+ static int modeset_open(int *out, const char *node);
+@@ -144,18 +147,45 @@ static int modeset_open(int *out, const char *node)
+ * }
+ */
+
+-struct modeset_dev {
+- struct modeset_dev *next;
++/*
++ * Previously, we used the modeset_dev objects to hold buffer informations, too.
++ * Technically, we could have split them but avoided this to make the
++ * example simpler.
++ * However, in this example we need 2 buffers. One back buffer and one front
++ * buffer. So we introduce a new structure modeset_buf which contains everything
++ * related to a single buffer. Each device now gets an array of two of these
++ * buffers.
++ * Each buffer consists of width, height, stride, size, handle, map and fb-id.
++ * They have the same meaning as before.
++ *
++ * Each device also gets a new integer field: front_buf. This field contains the
++ * index of the buffer that is currently used as front buffer / scanout buffer.
++ * In our example it can be 0 or 1. We flip it by using XOR:
++ * dev->front_buf ^= dev->front_buf
++ *
++ * Everything else stays the same.
++ */
+
++struct modeset_buf {
+ uint32_t width;
+ uint32_t height;
+ uint32_t stride;
+ uint32_t size;
+ uint32_t handle;
+ void *map;
++ uint32_t fb;
++};
++
++struct modeset_dev {
++ struct modeset_dev *next;
++
++ uint32_t width;
++ uint32_t height;
++
++ unsigned int front_buf;
++ struct modeset_buf bufs[2];
+
+ drmModeModeInfo mode;
+- uint32_t fb;
+ uint32_t conn;
+ uint32_t crtc;
+ drmModeCrtc *saved_crtc;
+@@ -292,10 +322,15 @@ static int modeset_setup_dev(int fd, drmModeRes *res, drmModeConnector *conn,
+ return -EFAULT;
+ }
+
+- /* copy the mode information into our device structure */
++ /* copy the mode information into our device structure and into both
++ * buffers */
+ memcpy(&dev->mode, &conn->modes[0], sizeof(dev->mode));
+ dev->width = conn->modes[0].hdisplay;
+ dev->height = conn->modes[0].vdisplay;
++ dev->bufs[0].width = dev->width;
++ dev->bufs[0].height = dev->height;
++ dev->bufs[1].width = dev->width;
++ dev->bufs[1].height = dev->height;
+ fprintf(stderr, "mode for connector %u is %ux%u\n",
+ conn->connector_id, dev->width, dev->height);
+
+@@ -307,14 +342,30 @@ static int modeset_setup_dev(int fd, drmModeRes *res, drmModeConnector *conn,
+ return ret;
+ }
+
+- /* create a framebuffer for this CRTC */
+- ret = modeset_create_fb(fd, dev);
++ /* create framebuffer #1 for this CRTC */
++ ret = modeset_create_fb(fd, &dev->bufs[0]);
+ if (ret) {
+ fprintf(stderr, "cannot create framebuffer for connector %u\n",
+ conn->connector_id);
+ return ret;
+ }
+
++ /* create framebuffer #2 for this CRTC */
++ ret = modeset_create_fb(fd, &dev->bufs[1]);
++ if (ret) {
++ fprintf(stderr, "cannot create framebuffer for connector %u\n",
++ conn->connector_id);
++ modeset_destroy_fb(fd, &dev->bufs[0]);
++ return ret;
++ }
++
++ if (dev->bufs[0].size != dev->bufs[1].size) {
++ fprintf(stderr, "front buffer size %" PRIu32 " does not match "
++ "back buffer size %" PRIu32 "\n",
++ dev->bufs[0].size, dev->bufs[1].size);
++ return -1;
++ }
++
+ return 0;
+ }
+
+@@ -441,7 +492,7 @@ static int modeset_find_crtc(int fd, drmModeRes *res, drmModeConnector *conn,
+ * memory directly via the dev->map memory map.
+ */
+
+-static int modeset_create_fb(int fd, struct modeset_dev *dev)
++static int modeset_create_fb(int fd, struct modeset_buf *buf)
+ {
+ struct drm_mode_create_dumb creq;
+ struct drm_mode_destroy_dumb dreq;
+@@ -450,8 +501,8 @@ static int modeset_create_fb(int fd, struct modeset_dev *dev)
+
+ /* create dumb buffer */
+ memset(&creq, 0, sizeof(creq));
+- creq.width = dev->width;
+- creq.height = dev->height;
++ creq.width = buf->width;
++ creq.height = buf->height;
+ creq.bpp = 32;
+ ret = drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &creq);
+ if (ret < 0) {
+@@ -459,13 +510,13 @@ static int modeset_create_fb(int fd, struct modeset_dev *dev)
+ errno);
+ return -errno;
+ }
+- dev->stride = creq.pitch;
+- dev->size = creq.size;
+- dev->handle = creq.handle;
++ buf->stride = creq.pitch;
++ buf->size = creq.size;
++ buf->handle = creq.handle;
+
+ /* create framebuffer object for the dumb-buffer */
+- ret = drmModeAddFB(fd, dev->width, dev->height, 24, 32, dev->stride,
+- dev->handle, &dev->fb);
++ ret = drmModeAddFB(fd, buf->width, buf->height, 24, 32, buf->stride,
++ buf->handle, &buf->fb);
+ if (ret) {
+ fprintf(stderr, "cannot create framebuffer (%d): %m\n",
+ errno);
+@@ -475,7 +526,7 @@ static int modeset_create_fb(int fd, struct modeset_dev *dev)
+
+ /* prepare buffer for memory mapping */
+ memset(&mreq, 0, sizeof(mreq));
+- mreq.handle = dev->handle;
++ mreq.handle = buf->handle;
+ ret = drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &mreq);
+ if (ret) {
+ fprintf(stderr, "cannot map dumb buffer (%d): %m\n",
+@@ -485,9 +536,9 @@ static int modeset_create_fb(int fd, struct modeset_dev *dev)
+ }
+
+ /* perform actual memory mapping */
+- dev->map = mmap(0, dev->size, PROT_READ | PROT_WRITE, MAP_SHARED,
++ buf->map = mmap(0, buf->size, PROT_READ | PROT_WRITE, MAP_SHARED,
+ fd, mreq.offset);
+- if (dev->map == MAP_FAILED) {
++ if (buf->map == MAP_FAILED) {
+ fprintf(stderr, "cannot mmap dumb buffer (%d): %m\n",
+ errno);
+ ret = -errno;
+@@ -495,23 +546,73 @@ static int modeset_create_fb(int fd, struct modeset_dev *dev)
+ }
+
+ /* clear the framebuffer to 0 */
+- memset(dev->map, 0, dev->size);
++ memset(buf->map, 0, buf->size);
+
+ return 0;
+
+ err_fb:
+- drmModeRmFB(fd, dev->fb);
++ drmModeRmFB(fd, buf->fb);
+ err_destroy:
+ memset(&dreq, 0, sizeof(dreq));
+- dreq.handle = dev->handle;
++ dreq.handle = buf->handle;
+ drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq);
+ return ret;
+ }
+
++/*
++ * modeset_destroy_fb() is a new function. It does exactly the reverse of
++ * modeset_create_fb() and destroys a single framebuffer. The modeset.c example
++ * used to do this directly in modeset_cleanup().
++ * We simply unmap the buffer, remove the drm-FB and destroy the memory buffer.
++ */
++
++static void modeset_destroy_fb(int fd, struct modeset_buf *buf)
++{
++ struct drm_mode_destroy_dumb dreq;
++
++ /* unmap buffer */
++ munmap(buf->map, buf->size);
++
++ /* delete framebuffer */
++ drmModeRmFB(fd, buf->fb);
++
++ /* delete dumb buffer */
++ memset(&dreq, 0, sizeof(dreq));
++ dreq.handle = buf->handle;
++ drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq);
++}
++
+ static void psplash_drm_flip(PSplashCanvas *canvas, int sync)
+ {
+- (void)canvas;
++ PSplashDRM *drm = canvas->priv;
++ struct modeset_buf *buf;
++ int ret;
++
+ (void)sync;
++
++ /* pick a back buffer */
++ buf = &modeset_list->bufs[modeset_list->front_buf ^ 1];
++
++ /* set back buffer as a front buffer */
++ ret = drmModeSetCrtc(drm->fd, modeset_list->crtc, buf->fb, 0, 0,
++ &modeset_list->conn, 1, &modeset_list->mode);
++ if (ret) {
++ fprintf(stderr, "cannot flip CRTC for connector %u (%d): %m\n",
++ modeset_list->conn, errno);
++ return;
++ }
++
++ /* update front buffer index */
++ modeset_list->front_buf ^= 1;
++
++ /* update back buffer pointer */
++ drm->canvas.data = modeset_list->bufs[modeset_list->front_buf ^ 1].map;
++
++ /* Sync new front to new back when requested */
++ if (sync)
++ memcpy(modeset_list->bufs[modeset_list->front_buf ^ 1].map,
++ modeset_list->bufs[modeset_list->front_buf].map,
++ modeset_list->bufs[0].size);
+ }
+
+ /*
+@@ -555,6 +656,7 @@ PSplashDRM* psplash_drm_new(int angle, int dev_id)
+ int ret;
+ char card[] = "/dev/dri/card0";
+ struct modeset_dev *iter;
++ struct modeset_buf *buf;
+
+ if ((drm = malloc(sizeof(*drm))) == NULL) {
+ perror("malloc");
+@@ -583,18 +685,28 @@ PSplashDRM* psplash_drm_new(int angle, int dev_id)
+ /* perform actual modesetting on each found connector+CRTC */
+ for (iter = modeset_list; iter; iter = iter->next) {
+ iter->saved_crtc = drmModeGetCrtc(drm->fd, iter->crtc);
+- ret = drmModeSetCrtc(drm->fd, iter->crtc, iter->fb, 0, 0,
++ buf = &iter->bufs[iter->front_buf];
++ ret = drmModeSetCrtc(drm->fd, iter->crtc, buf->fb, 0, 0,
+ &iter->conn, 1, &iter->mode);
+ if (ret)
+ fprintf(stderr, "cannot set CRTC for connector %u (%d): %m\n",
+ iter->conn, errno);
+ }
+
+- drm->canvas.data = modeset_list->map;
++ drm->canvas.data = modeset_list->bufs[modeset_list->front_buf ^ 1].map;
+ drm->canvas.width = modeset_list->width;
+ drm->canvas.height = modeset_list->height;
+ drm->canvas.bpp = 32;
+- drm->canvas.stride = modeset_list->stride;
++
++ if (modeset_list->bufs[0].stride != modeset_list->bufs[1].stride) {
++ fprintf(stderr, "front buffer stride %" PRIu32 " does not match"
++ " back buffer stride %" PRIu32 "\n",
++ modeset_list->bufs[0].stride,
++ modeset_list->bufs[1].stride);
++ goto error;
++ }
++ drm->canvas.stride = modeset_list->bufs[0].stride;
++
+ drm->canvas.angle = angle;
+ drm->canvas.rgbmode = RGB888;
+
+@@ -614,7 +726,6 @@ error:
+ void psplash_drm_destroy(PSplashDRM *drm)
+ {
+ struct modeset_dev *iter;
+- struct drm_mode_destroy_dumb dreq;
+
+ if (!drm)
+ return;
+@@ -635,16 +746,9 @@ void psplash_drm_destroy(PSplashDRM *drm)
+ &iter->saved_crtc->mode);
+ drmModeFreeCrtc(iter->saved_crtc);
+
+- /* unmap buffer */
+- munmap(iter->map, iter->size);
+-
+- /* delete framebuffer */
+- drmModeRmFB(drm->fd, iter->fb);
+-
+- /* delete dumb buffer */
+- memset(&dreq, 0, sizeof(dreq));
+- dreq.handle = iter->handle;
+- drmIoctl(drm->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq);
++ /* destroy framebuffers */
++ modeset_destroy_fb(drm->fd, &iter->bufs[1]);
++ modeset_destroy_fb(drm->fd, &iter->bufs[0]);
+
+ /* free allocated memory */
+ free(iter);
+--
+2.25.1
+