From 67a93c94e038884b1607921aef3d40a7f11d95bd Mon Sep 17 00:00:00 2001 From: Linex <26711215+linex-cd@users.noreply.github.com> Date: Tue, 6 Jun 2023 11:56:00 +0800 Subject: [PATCH 1/4] Add support shm key for rawfb option Sometime shmid is not same on different time or system, we should use a constant ID for shm. Here use shm key to instead. --- doc/OPTIONS.md | 6 +++++- src/screen.c | 13 +++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/doc/OPTIONS.md b/doc/OPTIONS.md index 29aea5b..37273ad 100644 --- a/doc/OPTIONS.md +++ b/doc/OPTIONS.md @@ -4395,8 +4395,12 @@ Options: whole frame). For shared memory segments string is of the form: - "shm:N@WxHxB" which specifies a shmid N and with + "shm:N@WxHxB" which specifies a shm key(or a shmid) N and with WxHxB as above. See shmat(1) and ipcs(1) + + Since shm key can be defined constantly, you should use + shm key rather than shmid. Unless you have a special purpose, + a mutable shmid may cause problems. If you do not supply a type "map" is assumed if the file exists (see the next paragraphs for some diff --git a/src/screen.c b/src/screen.c index a89cb21..0905bfb 100644 --- a/src/screen.c +++ b/src/screen.c @@ -2130,6 +2130,19 @@ if (db) fprintf(stderr, "initialize_raw_fb reset\n"); if (sscanf(str, "shm:%d", &shmid) == 1) { /* shm:N */ #if HAVE_XSHM || HAVE_SHMAT + /* try to use shm key*/ + key_t shmkey = 0; + size_t size = 0; + int newshmid = -1; + + shmkey = shmid; + size = w * h * b / 8; + newshmid = shmget(shmkey, size, 0); + if (newshmid != -1) { + rfbLog("rawfb: use %d as shm key, shmid is %d \n", shmid, newshmid); + shmid = newshmid; + } + raw_fb_addr = (char *) shmat(shmid, 0, SHM_RDONLY); if (! raw_fb_addr) { rfbLogEnable(1); From da919499a71f9f89914f217e3deb8cfd9821d80b Mon Sep 17 00:00:00 2001 From: Linex <26711215+linex-cd@users.noreply.github.com> Date: Wed, 7 Jun 2023 13:01:35 +0800 Subject: [PATCH 2/4] Add DRM support access GPU with DRM, this will support x11 and wayland --- configure.ac | 22 ++++++++++ doc/OPTIONS.md | 5 +++ src/Makefile.am | 1 + src/screen.c | 105 +++++++++++++++++++++++++++++++++++++++++++++++- src/x11vnc.h | 4 ++ 5 files changed, 135 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 6b62ac5..e841577 100644 --- a/configure.ac +++ b/configure.ac @@ -22,6 +22,12 @@ AC_ARG_WITH(ssl, [ --without-ssl disable support for openssl libssl] [ --with-ssl=DIR use openssl include/library files in DIR],,) +AH_TEMPLATE(HAVE_LIBDRM, [drm library present]) +AC_ARG_WITH(drm, +[ --without-drm disable support for openssl libdrm] +[ --with-drm=DIR use drm include/library files in DIR],,) + + if test "x$with_crypto" != "xno" -a "x$with_ssl" != "xno"; then if test ! -z "$with_ssl" -a "x$with_ssl" != "xyes"; then saved_CPPFLAGS="$CPPFLAGS" @@ -59,6 +65,22 @@ if test "x$with_crypt" != "xno"; then fi AC_SUBST(CRYPT_LIBS) +AH_TEMPLATE(HAVE_LIBDRM, [libdrm library present]) +AC_ARG_WITH(drm, +[ --without-drm disable support for libdrm],,) +if test "x$with_drm" != "xno"; then + AC_CHECK_FUNCS([drm], HAVE_LIBC_DRM="true") + if test -z "$HAVE_LIBC_DRM"; then + AC_CHECK_LIB(drm, drmModeGetResources, + DRM_LIBS="-ldrm" + [AC_DEFINE(HAVE_LIBDRM)], ,) + + + CPPFLAGS="$saved_CPPFLAGS -I/usr/include/drm/" + fi +fi +AC_SUBST(DRM_LIBS) + AH_TEMPLATE(HAVE_X509_PRINT_EX_FP, [open ssl X509_print_ex_fp available]) if test "x$with_ssl" != "xno"; then if test "x$HAVE_LIBCRYPTO" = "xtrue"; then diff --git a/doc/OPTIONS.md b/doc/OPTIONS.md index 37273ad..38654cd 100644 --- a/doc/OPTIONS.md +++ b/doc/OPTIONS.md @@ -4402,6 +4402,10 @@ Options: shm key rather than shmid. Unless you have a special purpose, a mutable shmid may cause problems. + If there is a new desktop like Wayland, use "drm:" to access + GPU FrameBuffer. If you do not know the GPU path, just use + "/dev/dri/card0". + If you do not supply a type "map" is assumed if the file exists (see the next paragraphs for some exceptions to this.) @@ -4451,6 +4455,7 @@ Options: Examples: -rawfb shm:210337933@800x600x32:ff/ff00/ff0000 + -rawfb drm:/dev/dri/card0@800x600x32:ff/ff00/ff0000 -rawfb map:/dev/fb0@1024x768x32 -rawfb map:/dev/fb0@800x480x16#800x960 -rawfb map:/tmp/Xvfb_screen0@640x480x8+3232 diff --git a/src/Makefile.am b/src/Makefile.am index 11168c7..dc2242e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -140,6 +140,7 @@ AM_CPPFLAGS = \ x11vnc_LDADD = \ $(LDADD) \ @SSL_LIBS@ \ + @DRM_LIBS@ \ @CRYPT_LIBS@ \ @X_LIBS@ \ @AVAHI_LIBS@ \ diff --git a/src/screen.c b/src/screen.c index 0905bfb..a14c98d 100644 --- a/src/screen.c +++ b/src/screen.c @@ -1636,6 +1636,7 @@ void linux_dev_fb_msg(char* q) { #define RAWFB_MMAP 1 #define RAWFB_FILE 2 #define RAWFB_SHM 3 +#define RAWFB_DRM 4 XImage *initialize_raw_fb(int reset) { char *str, *rstr, *q; @@ -1934,6 +1935,7 @@ if (db) fprintf(stderr, "initialize_raw_fb reset\n"); * -rawfb shm:163938442@640x480x32:ff/ff00/ff0000+3000 * -rawfb map:/path/to/file@640x480x32:ff/ff00/ff0000 * -rawfb file:/path/to/file@640x480x32:ff/ff00/ff0000 + * -rawfb drm:/dev/dri/card0@640x480x32:ff/ff00/ff0000 */ if (raw_fb_full_str) { @@ -2110,7 +2112,8 @@ if (db) fprintf(stderr, "initialize_raw_fb reset\n"); } if (strstr(str, "shm:") != str && strstr(str, "mmap:") != str && - strstr(str, "map:") != str && strstr(str, "file:") != str) { + strstr(str, "map:") != str && strstr(str, "file:") != str && + strstr(str, "drm:") != str ) { /* hmmm, not following directions, see if map: applies */ struct stat sbuf; if (stat(str, &sbuf) == 0) { @@ -2279,7 +2282,105 @@ if (db) fprintf(stderr, "initialize_raw_fb reset\n"); rfbLog("rawfb: seek file: %s\n", q); rfbLog(" W: %d H: %d B: %d sz: %d\n", w, h, b, size); } - } else { + } + + else if (strstr(str, "drm:") == str ) { + /* drm:D */ + /* drm:/dev/dri/card0 */ + + q = strchr(str, ':'); + q++; + + /* open DRM device */ + int fd = open(q, O_RDWR | O_CLOEXEC); + if (fd < 0) { + rfbLogEnable(1); + rfbLog("can not open drm device: %s\n", str); + clean_up_exit(1); + } + + /* get current CRTC */ + drmModeRes* res = drmModeGetResources(fd); + if (!res) { + rfbLogEnable(1); + rfbLog("can not read drm device: %s\n", str); + clean_up_exit(1); + } + + /* get first crtc */ + /* drmModeCrtc* crtc = drmModeGetCrtc(fd, res->crtcs[0]); */ + drmModeCrtc* crtc = 0; + drmModeFB* fb = 0; + int dma_buf_fd = 0; + rfbLog("drm crtc count:%d\n", res->count_crtcs); + for (int i = 0; i < res->count_crtcs; i++) { + + crtc = drmModeGetCrtc(fd, res->crtcs[i]); + if (crtc->mode_valid && crtc->buffer_id != 0) { + + fb = drmModeGetFB(fd, crtc->buffer_id); + + struct drm_prime_handle prime_handle = { + .handle = fb->handle, + .fd = -1, + .flags = 0 + }; + + if (ioctl(fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &prime_handle) < 0) { + drmModeFreeFB(fb); + drmModeFreeCrtc(crtc); + crtc = NULL; + } + else{ + dma_buf_fd = prime_handle.fd; + break; + + } + + + } + + } + + if (!crtc) { + rfbLogEnable(1); + rfbLog("no valid crtc for drm device: %s\n", str); + clean_up_exit(1); + } + + if (!dma_buf_fd) { + rfbLogEnable(1); + rfbLog("open CRTC err, please turn on your display. "); + clean_up_exit(1); + } + + + + /* get DMA-BUF size */ + off_t size = lseek(dma_buf_fd, 0, SEEK_END); + lseek(dma_buf_fd, 0, SEEK_SET); + rfbLog("dma buffer (%d) size=%ld\n", dma_buf_fd, size); + + /* mapping DMA-BUF to memory */ + void* map = mmap(NULL, size, PROT_READ, MAP_SHARED, dma_buf_fd, 0); + if (map == MAP_FAILED) { + rfbLogEnable(1); + rfbLog("mmap failed for drm device: %s\n", str); + clean_up_exit(1); + } + + /* clean resouces */ + /* close(dma_buf_fd); */ + drmModeFreeFB(fb); + drmModeFreeCrtc(crtc); + drmModeFreeResources(res); + close(fd); + + raw_fb_addr = (char*)map; + last_mode = RAWFB_DRM; + + } + else { rfbLogEnable(1); rfbLog("invalid rawfb str: %s\n", str); clean_up_exit(1); diff --git a/src/x11vnc.h b/src/x11vnc.h index 18d5feb..f89d2a2 100644 --- a/src/x11vnc.h +++ b/src/x11vnc.h @@ -69,6 +69,10 @@ so, delete this exception statement from your version. #include #include +/* drm access */ +#include +#include +#include /* we can now build under --without-x: */ #if HAVE_X11 From 4b18e9ef447dc9f89e22a9d77e1f5eb7fe1e15a6 Mon Sep 17 00:00:00 2001 From: Linex <26711215+linex-cd@users.noreply.github.com> Date: Fri, 9 Jun 2023 14:47:36 +0800 Subject: [PATCH 3/4] Fix a bug for shmget params. shmget should be 0 otherwise it would alloc a new shared memory but not for the frame buffer. --- doc/OPTIONS.md | 12 ++++++------ src/screen.c | 5 ++--- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/doc/OPTIONS.md b/doc/OPTIONS.md index 38654cd..8845687 100644 --- a/doc/OPTIONS.md +++ b/doc/OPTIONS.md @@ -4398,13 +4398,13 @@ Options: "shm:N@WxHxB" which specifies a shm key(or a shmid) N and with WxHxB as above. See shmat(1) and ipcs(1) - Since shm key can be defined constantly, you should use - shm key rather than shmid. Unless you have a special purpose, - a mutable shmid may cause problems. + Since shm key can be defined constantly, you should use + shm key rather than shmid. Unless you have a special purpose, + a mutable shmid may cause problems. - If there is a new desktop like Wayland, use "drm:" to access - GPU FrameBuffer. If you do not know the GPU path, just use - "/dev/dri/card0". + If there is a new desktop like Wayland, use "drm:" to access + GPU FrameBuffer. If you do not know the GPU path, just use + "/dev/dri/card0@WxHxB". If you do not supply a type "map" is assumed if the file exists (see the next paragraphs for some diff --git a/src/screen.c b/src/screen.c index a14c98d..91e2b5d 100644 --- a/src/screen.c +++ b/src/screen.c @@ -2135,12 +2135,11 @@ if (db) fprintf(stderr, "initialize_raw_fb reset\n"); #if HAVE_XSHM || HAVE_SHMAT /* try to use shm key*/ key_t shmkey = 0; - size_t size = 0; int newshmid = -1; shmkey = shmid; - size = w * h * b / 8; - newshmid = shmget(shmkey, size, 0); + + newshmid = shmget(shmkey, 0, 0); if (newshmid != -1) { rfbLog("rawfb: use %d as shm key, shmid is %d \n", shmid, newshmid); shmid = newshmid; From 48141aa140e98cfc686df23a515e25ef70e02c7a Mon Sep 17 00:00:00 2001 From: Linex <26711215+linex-cd@users.noreply.github.com> Date: Mon, 31 Jul 2023 18:31:42 +0800 Subject: [PATCH 4/4] fix drm configure while compiling. --- configure.ac | 4 ++-- src/screen.c | 8 +++++++- src/x11vnc.h | 3 +++ 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index e841577..40f148d 100644 --- a/configure.ac +++ b/configure.ac @@ -24,7 +24,7 @@ AC_ARG_WITH(ssl, AH_TEMPLATE(HAVE_LIBDRM, [drm library present]) AC_ARG_WITH(drm, -[ --without-drm disable support for openssl libdrm] +[ --without-drm disable support for library libdrm] [ --with-drm=DIR use drm include/library files in DIR],,) @@ -73,7 +73,7 @@ if test "x$with_drm" != "xno"; then if test -z "$HAVE_LIBC_DRM"; then AC_CHECK_LIB(drm, drmModeGetResources, DRM_LIBS="-ldrm" - [AC_DEFINE(HAVE_LIBDRM)], ,) + [AC_DEFINE(HAVE_LIBDRM) HAVE_LIBDRM="true"], ,) CPPFLAGS="$saved_CPPFLAGS -I/usr/include/drm/" diff --git a/src/screen.c b/src/screen.c index 91e2b5d..203e55a 100644 --- a/src/screen.c +++ b/src/screen.c @@ -2286,7 +2286,7 @@ if (db) fprintf(stderr, "initialize_raw_fb reset\n"); else if (strstr(str, "drm:") == str ) { /* drm:D */ /* drm:/dev/dri/card0 */ - +#if HAVE_LIBDRM q = strchr(str, ':'); q++; @@ -2377,6 +2377,12 @@ if (db) fprintf(stderr, "initialize_raw_fb reset\n"); raw_fb_addr = (char*)map; last_mode = RAWFB_DRM; +#else + rfbLogEnable(1); + rfbLog("x11vnc was compiled without drm support.\n"); + rfbLogPerror("drmModeGetResources"); + clean_up_exit(1); +#endif } else { diff --git a/src/x11vnc.h b/src/x11vnc.h index f89d2a2..86d63f7 100644 --- a/src/x11vnc.h +++ b/src/x11vnc.h @@ -69,11 +69,14 @@ so, delete this exception statement from your version. #include #include +#if HAVE_LIBDRM /* drm access */ #include #include #include +#endif + /* we can now build under --without-x: */ #if HAVE_X11