From b3e49987c5706612ee342c685dea799be596df6a Mon Sep 17 00:00:00 2001 From: Naoto Yamaguchi Date: Sun, 23 Apr 2023 20:25:45 +0900 Subject: Enable drm-lease support at psplash The upstream version of psplash is supporting fb based splash screen. On the other hand, drm lease infrastructure is not support fb. This patch enable drm-lease support at psplash. This work contributed by Hiroyuki Ishii at CES2023 demo development. Bug-AGL: SPEC-4766 Change-Id: I50b382c7f8ca4b46a8fb06fd649d0cfa49800c6d Signed-off-by: Naoto Yamaguchi --- ...-psplash-drm.c-Implement-double-buffering.patch | 350 +++++++++++++++++++++ 1 file changed, 350 insertions(+) create mode 100644 meta-agl-drm-lease/recipes-core/psplash/files/0015-psplash-drm.c-Implement-double-buffering.patch (limited to 'meta-agl-drm-lease/recipes-core/psplash/files/0015-psplash-drm.c-Implement-double-buffering.patch') 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 +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 +--- + 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 + #include + #include ++#include + #include + #include + #include +@@ -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 + -- cgit 1.2.3-korg