From 52d865c35960f0c1de4811d186dccee27359709c Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 18 Jun 2024 16:01:55 +0200 Subject: [PATCH 1/6] Avoid VNC updates for offscreen windows Windows aren't always directly shown, e.g. when the desktop is composited. We should not be sending screen updates for these as the framebuffer didn't actually change. In the case of CopyWindow, we're even sending the wrong screen data, which is how this bug was discovered. --- unix/xserver/hw/vnc/vncHooks.c | 69 ++++++++++++++++++++-------------- 1 file changed, 41 insertions(+), 28 deletions(-) diff --git a/unix/xserver/hw/vnc/vncHooks.c b/unix/xserver/hw/vnc/vncHooks.c index 3838c10dab..7fe35ada3d 100644 --- a/unix/xserver/hw/vnc/vncHooks.c +++ b/unix/xserver/hw/vnc/vncHooks.c @@ -1,5 +1,5 @@ /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * Copyright 2009-2017 Pierre Ossman for Cendio AB + * Copyright 2009-2024 Pierre Ossman for Cendio AB * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -469,39 +469,47 @@ static void vncHooksCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr pOldRegion) { int dx, dy; - BoxRec screen_box; - RegionRec copied, screen_rgn; + RegionRec copied; SCREEN_PROLOGUE(pWin->drawable.pScreen, CopyWindow); - RegionNull(&copied); - RegionCopy(&copied, pOldRegion); + if (is_visible(&pWin->drawable)) { + BoxRec screen_box; + RegionRec screen_rgn; - screen_box.x1 = 0; - screen_box.y1 = 0; - screen_box.x2 = pScreen->width; - screen_box.y2 = pScreen->height; + RegionNull(&copied); + RegionCopy(&copied, pOldRegion); - RegionInitBoxes(&screen_rgn, &screen_box, 1); + screen_box.x1 = 0; + screen_box.y1 = 0; + screen_box.x2 = pScreen->width; + screen_box.y2 = pScreen->height; - dx = pWin->drawable.x - ptOldOrg.x; - dy = pWin->drawable.y - ptOldOrg.y; + RegionInitBoxes(&screen_rgn, &screen_box, 1); - // RFB tracks copies in terms of destination rectangle, not source. - // We also need to copy with changes to the Window's clipping region. - // Finally, make sure we don't get copies to or from regions outside - // the framebuffer. - RegionIntersect(&copied, &copied, &screen_rgn); - RegionTranslate(&copied, dx, dy); - RegionIntersect(&copied, &copied, &screen_rgn); - RegionIntersect(&copied, &copied, &pWin->borderClip); + dx = pWin->drawable.x - ptOldOrg.x; + dy = pWin->drawable.y - ptOldOrg.y; + + // RFB tracks copies in terms of destination rectangle, not source. + // We also need to copy with changes to the Window's clipping region. + // Finally, make sure we don't get copies to or from regions outside + // the framebuffer. + RegionIntersect(&copied, &copied, &screen_rgn); + RegionTranslate(&copied, dx, dy); + RegionIntersect(&copied, &copied, &screen_rgn); + RegionIntersect(&copied, &copied, &pWin->borderClip); + + RegionUninit(&screen_rgn); + } else { + RegionNull(&copied); + dx = dy = 0; + } (*pScreen->CopyWindow) (pWin, ptOldOrg, pOldRegion); add_copied(pScreen, &copied, dx, dy); RegionUninit(&copied); - RegionUninit(&screen_rgn); SCREEN_EPILOGUE(CopyWindow); } @@ -512,18 +520,23 @@ static void vncHooksCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, static void vncHooksClearToBackground(WindowPtr pWin, int x, int y, int w, int h, Bool generateExposures) { - BoxRec box; RegionRec reg; SCREEN_PROLOGUE(pWin->drawable.pScreen, ClearToBackground); - box.x1 = x + pWin->drawable.x; - box.y1 = y + pWin->drawable.y; - box.x2 = w ? (box.x1 + w) : (pWin->drawable.x + pWin->drawable.width); - box.y2 = h ? (box.y1 + h) : (pWin->drawable.y + pWin->drawable.height); + if (is_visible(&pWin->drawable)) { + BoxRec box; - RegionInitBoxes(®, &box, 1); - RegionIntersect(®, ®, &pWin->clipList); + box.x1 = x + pWin->drawable.x; + box.y1 = y + pWin->drawable.y; + box.x2 = w ? (box.x1 + w) : (pWin->drawable.x + pWin->drawable.width); + box.y2 = h ? (box.y1 + h) : (pWin->drawable.y + pWin->drawable.height); + + RegionInitBoxes(®, &box, 1); + RegionIntersect(®, ®, &pWin->clipList); + } else { + RegionNull(®); + } (*pScreen->ClearToBackground) (pWin, x, y, w, h, generateExposures); From c30370df0878b823bd520a31567a69763259d5a5 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 6 Jun 2024 13:29:29 +0200 Subject: [PATCH 2/6] Fix includes for Xorg dri3 module It was incorrectly designed to only build properly if built as part of the "Xorg" server and could fail to build when just "Xvnc" was built. Backport of upstream commits 0ce93e5 and acc581c. --- unix/xserver120.patch | 71 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/unix/xserver120.patch b/unix/xserver120.patch index 2f555eebd1..82546dc9e1 100644 --- a/unix/xserver120.patch +++ b/unix/xserver120.patch @@ -28,6 +28,77 @@ Index: xserver/configure.ac hw/xnest/Makefile hw/xnest/man/Makefile hw/xwin/Makefile +Index: xserver/dri3/Makefile.am +=================================================================== +--- xserver.orig/dri3/Makefile.am ++++ xserver/dri3/Makefile.am +@@ -1,7 +1,7 @@ + noinst_LTLIBRARIES = libdri3.la + AM_CFLAGS = \ +- -DHAVE_XORG_CONFIG_H \ +- @DIX_CFLAGS@ @XORG_CFLAGS@ ++ @DIX_CFLAGS@ \ ++ @LIBDRM_CFLAGS@ + + libdri3_la_SOURCES = \ + dri3.h \ +Index: xserver/dri3/dri3.c +=================================================================== +--- xserver.orig/dri3/dri3.c ++++ xserver/dri3/dri3.c +@@ -20,10 +20,6 @@ + * OF THIS SOFTWARE. + */ + +-#ifdef HAVE_XORG_CONFIG_H +-#include +-#endif +- + #include "dri3_priv.h" + + #include +Index: xserver/dri3/dri3_priv.h +=================================================================== +--- xserver.orig/dri3/dri3_priv.h ++++ xserver/dri3/dri3_priv.h +@@ -23,6 +23,7 @@ + #ifndef _DRI3PRIV_H_ + #define _DRI3PRIV_H_ + ++#include "dix-config.h" + #include + #include "scrnintstr.h" + #include "misc.h" +Index: xserver/dri3/dri3_request.c +=================================================================== +--- xserver.orig/dri3/dri3_request.c ++++ xserver/dri3/dri3_request.c +@@ -20,10 +20,6 @@ + * OF THIS SOFTWARE. + */ + +-#ifdef HAVE_XORG_CONFIG_H +-#include +-#endif +- + #include "dri3_priv.h" + #include + #include +Index: xserver/dri3/dri3_screen.c +=================================================================== +--- xserver.orig/dri3/dri3_screen.c ++++ xserver/dri3/dri3_screen.c +@@ -20,10 +20,6 @@ + * OF THIS SOFTWARE. + */ + +-#ifdef HAVE_XORG_CONFIG_H +-#include +-#endif +- + #include "dri3_priv.h" + #include + #include Index: xserver/hw/Makefile.am =================================================================== --- xserver.orig/hw/Makefile.am From 50048184a08f12cdf66064a5606fee2e981db9e8 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 21 Feb 2024 17:07:36 +0100 Subject: [PATCH 3/6] Add basic DRI3 support This provides buffer sync with the primary render node of the system (if available). By doing so, OpenGL and Vulkan can use the render node for acceleration. This first implementation is extremely pessimistic and synchronises buffers whenever there's even a slight chance they will be used. --- .../packages/deb/ubuntu-focal/debian/rules | 2 +- .../packages/deb/ubuntu-jammy/debian/rules | 4 +- contrib/packages/rpm/el7/SPECS/tigervnc.spec | 4 +- contrib/packages/rpm/el8/SPECS/tigervnc.spec | 4 +- contrib/packages/rpm/el9/SPECS/tigervnc.spec | 4 +- unix/xserver/hw/vnc/Makefile.am | 10 + unix/xserver/hw/vnc/vncDRI3.c | 494 +++++++++++ unix/xserver/hw/vnc/vncDRI3.h | 41 + unix/xserver/hw/vnc/vncDRI3Draw.c | 785 ++++++++++++++++++ unix/xserver/hw/vnc/xvnc.c | 7 + unix/xserver120.patch | 99 ++- unix/xserver21.1.1.patch | 38 - unix/xserver21.patch | 67 ++ 13 files changed, 1474 insertions(+), 85 deletions(-) create mode 100644 unix/xserver/hw/vnc/vncDRI3.c create mode 100644 unix/xserver/hw/vnc/vncDRI3.h create mode 100644 unix/xserver/hw/vnc/vncDRI3Draw.c delete mode 100644 unix/xserver21.1.1.patch create mode 100644 unix/xserver21.patch diff --git a/contrib/packages/deb/ubuntu-focal/debian/rules b/contrib/packages/deb/ubuntu-focal/debian/rules index afb7830a39..0245a065f4 100644 --- a/contrib/packages/deb/ubuntu-focal/debian/rules +++ b/contrib/packages/deb/ubuntu-focal/debian/rules @@ -102,7 +102,7 @@ config-stamp: xorg-source-stamp --enable-xdmcp \ --enable-xdm-auth-1 \ --enable-glx \ - --disable-dri --enable-dri2 --disable-dri3 \ + --disable-dri --enable-dri2 --enable-dri3 \ --enable-xinerama \ --enable-xf86vidmode \ --enable-xace \ diff --git a/contrib/packages/deb/ubuntu-jammy/debian/rules b/contrib/packages/deb/ubuntu-jammy/debian/rules index 02e798c9ff..1b4fd6f882 100644 --- a/contrib/packages/deb/ubuntu-jammy/debian/rules +++ b/contrib/packages/deb/ubuntu-jammy/debian/rules @@ -45,7 +45,7 @@ XORG_SOURCE_ARCHIVE = /usr/src/xorg-server.tar.xz xorg-source-stamp: $(XORG_SOURCE_ARCHIVE) tar -C unix/xserver -axf $(XORG_SOURCE_ARCHIVE) --strip-components=1 - cd unix/xserver && patch -p1 < ../xserver21.1.1.patch + cd unix/xserver && patch -p1 < ../xserver21.patch patch -p1 < debian/xorg-source-patches/516_tigervnc-xorg-manpages.patch touch xorg-source-stamp @@ -102,7 +102,7 @@ config-stamp: xorg-source-stamp --enable-xdmcp \ --enable-xdm-auth-1 \ --enable-glx \ - --disable-dri --enable-dri2 --disable-dri3 \ + --disable-dri --enable-dri2 --enable-dri3 \ --enable-xinerama \ --enable-xf86vidmode \ --enable-xace \ diff --git a/contrib/packages/rpm/el7/SPECS/tigervnc.spec b/contrib/packages/rpm/el7/SPECS/tigervnc.spec index 38a5c49b88..ee3baed808 100644 --- a/contrib/packages/rpm/el7/SPECS/tigervnc.spec +++ b/contrib/packages/rpm/el7/SPECS/tigervnc.spec @@ -27,7 +27,7 @@ BuildRequires: xorg-x11-server-source BuildRequires: libXext-devel, libX11-devel, libXi-devel, libXfixes-devel BuildRequires: libXdamage-devel, libXrandr-devel, libXt-devel, libXdmcp-devel BuildRequires: libXinerama-devel, mesa-libGL-devel, libxshmfence-devel -BuildRequires: pixman-devel, libdrm-devel, +BuildRequires: pixman-devel, libdrm-devel, mesa-libgbm-devel BuildRequires: xorg-x11-util-macros, xorg-x11-xtrans-devel, libXtst-devel BuildRequires: xorg-x11-font-utils BuildRequires: libXfont2-devel @@ -159,7 +159,7 @@ autoreconf -fiv --with-pic --disable-static \ --with-default-font-path="catalogue:%{_sysconfdir}/X11/fontpath.d,built-ins" \ --with-xkb-output=%{_localstatedir}/lib/xkb \ - --enable-glx --disable-dri --enable-dri2 --disable-dri3 \ + --enable-glx --disable-dri --enable-dri2 --enable-dri3 \ --disable-unit-tests \ --disable-config-hal \ --disable-config-udev \ diff --git a/contrib/packages/rpm/el8/SPECS/tigervnc.spec b/contrib/packages/rpm/el8/SPECS/tigervnc.spec index 619ad41403..307e26f6b2 100644 --- a/contrib/packages/rpm/el8/SPECS/tigervnc.spec +++ b/contrib/packages/rpm/el8/SPECS/tigervnc.spec @@ -28,7 +28,7 @@ BuildRequires: xorg-x11-server-source BuildRequires: libXext-devel, libX11-devel, libXi-devel, libXfixes-devel BuildRequires: libXdamage-devel, libXrandr-devel, libXt-devel, libXdmcp-devel BuildRequires: libXinerama-devel, mesa-libGL-devel, libxshmfence-devel -BuildRequires: pixman-devel, libdrm-devel, +BuildRequires: pixman-devel, libdrm-devel, mesa-libgbm-devel BuildRequires: xorg-x11-util-macros, xorg-x11-xtrans-devel, libXtst-devel BuildRequires: xorg-x11-font-utils BuildRequires: libXfont2-devel @@ -152,7 +152,7 @@ autoreconf -fiv --with-pic --disable-static \ --with-default-font-path="catalogue:%{_sysconfdir}/X11/fontpath.d,built-ins" \ --with-xkb-output=%{_localstatedir}/lib/xkb \ - --enable-glx --disable-dri --enable-dri2 --disable-dri3 \ + --enable-glx --disable-dri --enable-dri2 --enable-dri3 \ --disable-unit-tests \ --disable-config-hal \ --disable-config-udev \ diff --git a/contrib/packages/rpm/el9/SPECS/tigervnc.spec b/contrib/packages/rpm/el9/SPECS/tigervnc.spec index 88d82dc496..5d120bc0e6 100644 --- a/contrib/packages/rpm/el9/SPECS/tigervnc.spec +++ b/contrib/packages/rpm/el9/SPECS/tigervnc.spec @@ -28,7 +28,7 @@ BuildRequires: xorg-x11-server-source BuildRequires: libXext-devel, libX11-devel, libXi-devel, libXfixes-devel BuildRequires: libXdamage-devel, libXrandr-devel, libXt-devel, libXdmcp-devel BuildRequires: libXinerama-devel, mesa-libGL-devel, libxshmfence-devel -BuildRequires: pixman-devel, libdrm-devel, +BuildRequires: pixman-devel, libdrm-devel, mesa-libgbm-devel BuildRequires: xorg-x11-util-macros, xorg-x11-xtrans-devel, libXtst-devel BuildRequires: libXfont2-devel # SELinux @@ -151,7 +151,7 @@ autoreconf -fiv --with-pic --disable-static \ --with-default-font-path="catalogue:%{_sysconfdir}/X11/fontpath.d,built-ins" \ --with-xkb-output=%{_localstatedir}/lib/xkb \ - --enable-glx --disable-dri --enable-dri2 --disable-dri3 \ + --enable-glx --disable-dri --enable-dri2 --enable-dri3 \ --disable-unit-tests \ --disable-config-hal \ --disable-config-udev \ diff --git a/unix/xserver/hw/vnc/Makefile.am b/unix/xserver/hw/vnc/Makefile.am index f9ed19d949..f937218325 100644 --- a/unix/xserver/hw/vnc/Makefile.am +++ b/unix/xserver/hw/vnc/Makefile.am @@ -42,6 +42,8 @@ Xvnc_SOURCES = xvnc.c \ # recommendation for coaxing automake. nodist_EXTRA_Xvnc_SOURCES = dummy.cxx +Xvnc_CPPFLAGS = $(AM_CPPFLAGS) + LOCAL_LIBS = \ $(XVNC_LIBS) \ $(XSERVER_LIBS) \ @@ -53,6 +55,14 @@ Xvnc_LDADD = $(LOCAL_LIBS) $(XSERVER_SYS_LIBS) $(XVNC_SYS_LIBS) Xvnc_LDFLAGS = $(LD_EXPORT_SYMBOLS_FLAG) +if DRI3 +Xvnc_SOURCES += vncDRI3.h vncDRI3.c vncDRI3Draw.c +Xvnc_CPPFLAGS += \ + -I$(top_srcdir)/dri3 \ + $(GBM_CFLAGS) +Xvnc_LDADD += $(GBM_LIBS) +endif + libvnc_la_LTLIBRARIES = libvnc.la libvnc_ladir = $(moduledir)/extensions diff --git a/unix/xserver/hw/vnc/vncDRI3.c b/unix/xserver/hw/vnc/vncDRI3.c new file mode 100644 index 0000000000..3d261667a2 --- /dev/null +++ b/unix/xserver/hw/vnc/vncDRI3.c @@ -0,0 +1,494 @@ +/* Copyright 2024 Pierre Ossman for Cendio AB + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include +#include +#include + +#ifdef HAVE_GBM +#include +#endif + +#include "vncDRI3.h" +#include +#include +#include + +#ifdef FB_ACCESS_WRAPPER +#error "This code is not compatible with accessors" +#endif + +static DevPrivateKeyRec vncDRI3ScreenPrivateKey; +static DevPrivateKeyRec vncDRI3PixmapPrivateKey; + +typedef struct vncDRI3ScreenPrivate { + CloseScreenProcPtr CloseScreen; + + DestroyPixmapProcPtr DestroyPixmap; + +#ifdef HAVE_GBM + const char *devicePath; + struct gbm_device *device; + int fd; +#endif +} vncDRI3ScreenPrivateRec, *vncDRI3ScreenPrivatePtr; + +typedef struct vncDRI3PixmapPrivate { +#ifdef HAVE_GBM + struct gbm_bo *bo; +#endif +} vncDRI3PixmapPrivateRec, *vncDRI3PixmapPrivatePtr; + +#define wrap(priv, real, mem, func) {\ + priv->mem = real->mem; \ + real->mem = func; \ +} + +#define unwrap(priv, real, mem) {\ + real->mem = priv->mem; \ +} + +static inline vncDRI3ScreenPrivatePtr vncDRI3ScreenPrivate(ScreenPtr screen) +{ + return (vncDRI3ScreenPrivatePtr)dixLookupPrivate(&(screen)->devPrivates, &vncDRI3ScreenPrivateKey); +} + +static inline vncDRI3PixmapPrivatePtr vncDRI3PixmapPrivate(PixmapPtr pixmap) +{ + return (vncDRI3PixmapPrivatePtr)dixLookupPrivate(&(pixmap)->devPrivates, &vncDRI3PixmapPrivateKey); +} + +static int vncDRI3Open(ScreenPtr screen, RRProviderPtr provider, + int *fd) +{ +#ifdef HAVE_GBM + vncDRI3ScreenPrivatePtr screenPriv = vncDRI3ScreenPrivate(screen); + + *fd = open(screenPriv->devicePath, O_RDWR|O_CLOEXEC); + if (*fd < 0) + return BadAlloc; + + return Success; +#else + return BadAlloc; +#endif +} + +/* Taken from glamor */ +#ifdef HAVE_GBM +static uint32_t gbm_format_for_depth(CARD8 depth) +{ + switch (depth) { + case 16: + return GBM_FORMAT_RGB565; + case 24: + return GBM_FORMAT_XRGB8888; + case 30: + return GBM_FORMAT_ARGB2101010; + default: + ErrorF("unexpected depth: %d\n", depth); + case 32: + return GBM_FORMAT_ARGB8888; + } +} +#endif + +static PixmapPtr vncPixmapFromFd(ScreenPtr screen, int fd, + CARD16 width, CARD16 height, + CARD16 stride, CARD8 depth, + CARD8 bpp) +{ +#ifdef HAVE_GBM + vncDRI3ScreenPrivatePtr screenPriv = vncDRI3ScreenPrivate(screen); + vncDRI3PixmapPrivatePtr pixmapPriv; + + struct gbm_import_fd_data data; + struct gbm_bo *bo; + PixmapPtr pixmap; + + if (bpp != sizeof(FbBits)*8) { + ErrorF("Incompatible bits per pixel given for GPU buffer\n"); + return NULL; + } + + if ((stride % sizeof(FbBits)) != 0) { + ErrorF("Incompatible stride given for GPU buffer\n"); + return NULL; + } + + data.fd = fd; + data.width = width; + data.height = height; + data.stride = stride; + data.format = gbm_format_for_depth(depth); + + bo = gbm_bo_import(screenPriv->device, GBM_BO_IMPORT_FD, &data, + GBM_BO_USE_RENDERING | GBM_BO_USE_LINEAR); + if (bo == NULL) + return NULL; + + pixmap = screen->CreatePixmap(screen, width, height, depth, 0); + + pixmapPriv = vncDRI3PixmapPrivate(pixmap); + pixmapPriv->bo = bo; + + vncDRI3SyncPixmapFromGPU(pixmap); + + return pixmap; +#else + return NULL; +#endif +} + +static Bool vncDRI3DestroyPixmap(PixmapPtr pixmap) +{ + ScreenPtr screen = pixmap->drawable.pScreen; + vncDRI3ScreenPrivatePtr screenPriv = vncDRI3ScreenPrivate(screen); + Bool ret; + +#ifdef HAVE_GBM + if (pixmap->refcnt == 1) { + vncDRI3PixmapPrivatePtr pixmapPriv = vncDRI3PixmapPrivate(pixmap); + + if (pixmapPriv->bo != NULL) { + gbm_bo_destroy(pixmapPriv->bo); + pixmapPriv->bo = NULL; + } + } +#endif + + unwrap(screenPriv, screen, DestroyPixmap); + ret = screen->DestroyPixmap(pixmap); + wrap(screenPriv, screen, DestroyPixmap, vncDRI3DestroyPixmap); + + return ret; +} + +#ifdef HAVE_GBM +static int vncDRI3FdFromPixmapVisitWindow(WindowPtr window, void *data) +{ + ScreenPtr screen = window->drawable.pScreen; + PixmapPtr pixmap = data; + + if ((*screen->GetWindowPixmap)(window) == pixmap) + window->drawable.serialNumber = NEXT_SERIAL_NUMBER; + + return WT_WALKCHILDREN; +} +#endif + +static int vncFdFromPixmap(ScreenPtr screen, PixmapPtr pixmap, + CARD16 *stride, CARD32 *size) +{ +#ifdef HAVE_GBM + vncDRI3ScreenPrivatePtr screenPriv = vncDRI3ScreenPrivate(screen); + vncDRI3PixmapPrivatePtr pixmapPriv = vncDRI3PixmapPrivate(pixmap); + + if (pixmap->drawable.bitsPerPixel != sizeof(FbBits)*8) { + ErrorF("Incompatible bits per pixel given for pixmap\n"); + return -1; + } + + if (pixmapPriv->bo == NULL) { + /* GBM_BO_USE_LINEAR ? */ + pixmapPriv->bo = gbm_bo_create(screenPriv->device, + pixmap->drawable.width, + pixmap->drawable.height, + gbm_format_for_depth(pixmap->drawable.depth), + GBM_BO_USE_RENDERING | GBM_BO_USE_LINEAR); + if (pixmapPriv->bo == NULL) { + ErrorF("Failed to create GPU buffer: %s\n", strerror(errno)); + return -1; + } + + if ((gbm_bo_get_stride(pixmapPriv->bo) % sizeof(FbBits)) != 0) { + ErrorF("Incompatible stride for created GPU buffer\n"); + gbm_bo_destroy(pixmapPriv->bo); + pixmapPriv->bo = NULL; + return -1; + } + + /* Force re-validation of any gc:s */ + pixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER; + WalkTree(screen, vncDRI3FdFromPixmapVisitWindow, pixmap); + } + + vncDRI3SyncPixmapToGPU(pixmap); + + *stride = gbm_bo_get_stride(pixmapPriv->bo); + /* FIXME */ + *size = *stride * gbm_bo_get_height(pixmapPriv->bo); + + return gbm_bo_get_fd(pixmapPriv->bo); +#else + return -1; +#endif +} + +Bool vncDRI3IsHardwarePixmap(PixmapPtr pixmap) +{ +#ifdef HAVE_GBM + vncDRI3PixmapPrivatePtr pixmapPriv = vncDRI3PixmapPrivate(pixmap); + return pixmapPriv->bo != NULL; +#else + return FALSE; +#endif +} + +Bool vncDRI3IsHardwareDrawable(DrawablePtr drawable) +{ + PixmapPtr pixmap; + int xoff, yoff; + + fbGetDrawablePixmap(drawable, pixmap, xoff, yoff); + (void)xoff; + (void)yoff; + + return vncDRI3IsHardwarePixmap(pixmap); +} + +Bool vncDRI3SyncPixmapToGPU(PixmapPtr pixmap) +{ +#ifdef HAVE_GBM + vncDRI3PixmapPrivatePtr pixmapPriv = vncDRI3PixmapPrivate(pixmap); + + int width, height; + + FbBits *bo_data; + uint32_t bo_stride; + void *map_data; + uint32_t bo_bpp; + + FbBits *pixmap_data; + int pixmap_stride; + int pixmap_bpp; + + pixman_bool_t ret; + + if (pixmapPriv->bo == NULL) + return TRUE; + + width = gbm_bo_get_width(pixmapPriv->bo); + height = gbm_bo_get_height(pixmapPriv->bo); + + map_data = NULL; + bo_data = gbm_bo_map(pixmapPriv->bo, 0, 0, width, height, + GBM_BO_TRANSFER_WRITE, &bo_stride, &map_data); + if (bo_data == NULL) { + ErrorF("Could not map GPU buffer: %s\n", strerror(errno)); + return FALSE; + } + + bo_bpp = gbm_bo_get_bpp(pixmapPriv->bo); + assert(bo_bpp == sizeof(FbBits)*8); + assert((bo_stride % (bo_bpp/8)) == 0); + + fbGetPixmapBitsData(pixmap, pixmap_data, + pixmap_stride, pixmap_bpp); + assert(pixmap_data != NULL); + assert(pixmap_bpp == sizeof(FbBits)*8); + + assert(bo_bpp == pixmap_bpp); + + /* Try accelerated copy first */ + ret = pixman_blt((uint32_t*)pixmap_data, (uint32_t*)bo_data, + pixmap_stride, bo_stride / (bo_bpp/8), + pixmap_bpp, bo_bpp, 0, 0, 0, 0, width, height); + if (!ret) { + /* Fall back to slow pure C version */ + fbBlt(pixmap_data, pixmap_stride, 0, + bo_data, bo_stride / (bo_bpp/8), 0, + width * bo_bpp, height, + GXcopy, FB_ALLONES, bo_bpp, FALSE, FALSE); + } + + gbm_bo_unmap(pixmapPriv->bo, map_data); +#endif + + return TRUE; +} + +Bool vncDRI3SyncPixmapFromGPU(PixmapPtr pixmap) +{ +#ifdef HAVE_GBM + vncDRI3PixmapPrivatePtr pixmapPriv = vncDRI3PixmapPrivate(pixmap); + + int width, height; + + FbBits *bo_data; + uint32_t bo_stride; + void *map_data; + uint32_t bo_bpp; + + FbBits *pixmap_data; + int pixmap_stride; + int pixmap_bpp; + + pixman_bool_t ret; + + if (pixmapPriv->bo == NULL) + return TRUE; + + width = gbm_bo_get_width(pixmapPriv->bo); + height = gbm_bo_get_height(pixmapPriv->bo); + + map_data = NULL; + bo_data = gbm_bo_map(pixmapPriv->bo, 0, 0, width, height, + GBM_BO_TRANSFER_READ, &bo_stride, &map_data); + if (bo_data == NULL) { + ErrorF("Could not map GPU buffer: %s\n", strerror(errno)); + return FALSE; + } + + bo_bpp = gbm_bo_get_bpp(pixmapPriv->bo); + assert(bo_bpp == sizeof(FbBits)*8); + assert((bo_stride % (bo_bpp/8)) == 0); + + fbGetPixmapBitsData(pixmap, pixmap_data, + pixmap_stride, pixmap_bpp); + assert(pixmap_data != NULL); + assert(pixmap_bpp == sizeof(FbBits)*8); + + assert(bo_bpp == pixmap_bpp); + + /* Try accelerated copy first */ + ret = pixman_blt((uint32_t*)bo_data, (uint32_t*)pixmap_data, + bo_stride / (bo_bpp/8), pixmap_stride, + bo_bpp, pixmap_bpp, 0, 0, 0, 0, width, height); + if (!ret) { + /* Fall back to slow pure C version */ + fbBlt(bo_data, bo_stride / (bo_bpp/8), 0, + pixmap_data, pixmap_stride, 0, + width * bo_bpp, height, + GXcopy, FB_ALLONES, bo_bpp, FALSE, FALSE); + } + + gbm_bo_unmap(pixmapPriv->bo, map_data); +#endif + + return TRUE; +} + +Bool vncDRI3SyncDrawableToGPU(DrawablePtr drawable) +{ + PixmapPtr pixmap; + int xoff, yoff; + + fbGetDrawablePixmap(drawable, pixmap, xoff, yoff); + (void)xoff; + (void)yoff; + + return vncDRI3SyncPixmapToGPU(pixmap); +} + +Bool vncDRI3SyncDrawableFromGPU(DrawablePtr drawable) +{ + PixmapPtr pixmap; + int xoff, yoff; + + fbGetDrawablePixmap(drawable, pixmap, xoff, yoff); + (void)xoff; + (void)yoff; + + return vncDRI3SyncPixmapFromGPU(pixmap); +} + +static const dri3_screen_info_rec vncDRI3ScreenInfo = { + .version = 1, + + .open = vncDRI3Open, + .pixmap_from_fd = vncPixmapFromFd, + .fd_from_pixmap = vncFdFromPixmap, +}; + +static Bool vncDRI3CloseScreen(ScreenPtr screen) +{ + vncDRI3ScreenPrivatePtr screenPriv = vncDRI3ScreenPrivate(screen); + + unwrap(screenPriv, screen, CloseScreen); + + unwrap(screenPriv, screen, DestroyPixmap); + +#ifdef HAVE_GBM + gbm_device_destroy(screenPriv->device); + screenPriv->device = NULL; + + close(screenPriv->fd); + screenPriv->fd = -1; +#endif + + return (*screen->CloseScreen)(screen); +} + +Bool vncDRI3Init(ScreenPtr screen) +{ + vncDRI3ScreenPrivatePtr screenPriv; + + /* + * We don't queue any gbm operations, so we don't have to do anything + * more than simply activate this extension. + */ +#ifdef HAVE_XSHMFENCE + if (!miSyncShmScreenInit(screen)) + return FALSE; +#endif + + if (!dixRegisterPrivateKey(&vncDRI3ScreenPrivateKey, PRIVATE_SCREEN, + sizeof(vncDRI3ScreenPrivateRec))) + return FALSE; + if (!dixRegisterPrivateKey(&vncDRI3PixmapPrivateKey, PRIVATE_PIXMAP, + sizeof(vncDRI3PixmapPrivateRec))) + return FALSE; + + if (!vncDRI3DrawInit(screen)) + return FALSE; + +#ifdef HAVE_GBM + screenPriv = vncDRI3ScreenPrivate(screen); + + screenPriv->devicePath = "/dev/dri/renderD128"; + + screenPriv->fd = open(screenPriv->devicePath, O_RDWR|O_CLOEXEC); + if (screenPriv->fd < 0) { + ErrorF("Failed to open \"%s\": %s\n", + screenPriv->devicePath, strerror(errno)); + return FALSE; + } + + screenPriv->device = gbm_create_device(screenPriv->fd); + if (screenPriv->device == NULL) { + close(screenPriv->fd); + screenPriv->fd = -1; + ErrorF("Could create GPU render device\n"); + return FALSE; + } +#else + ErrorF("Built without GBM support\n"); + return FALSE; +#endif + + wrap(screenPriv, screen, CloseScreen, vncDRI3CloseScreen); + + wrap(screenPriv, screen, DestroyPixmap, vncDRI3DestroyPixmap); + + return dri3_screen_init(screen, &vncDRI3ScreenInfo); +} diff --git a/unix/xserver/hw/vnc/vncDRI3.h b/unix/xserver/hw/vnc/vncDRI3.h new file mode 100644 index 0000000000..636171bac7 --- /dev/null +++ b/unix/xserver/hw/vnc/vncDRI3.h @@ -0,0 +1,41 @@ +/* Copyright 2024 Pierre Ossman for Cendio AB + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#ifndef __VNCDRI3_H__ +#define __VNCDRI3_H__ + +#ifdef DRI3 + +#include + +Bool vncDRI3Init(ScreenPtr screen); + +Bool vncDRI3IsHardwarePixmap(PixmapPtr pixmap); +Bool vncDRI3IsHardwareDrawable(DrawablePtr drawable); + +Bool vncDRI3SyncPixmapToGPU(PixmapPtr pixmap); +Bool vncDRI3SyncPixmapFromGPU(PixmapPtr pixmap); + +Bool vncDRI3SyncDrawableToGPU(DrawablePtr drawable); +Bool vncDRI3SyncDrawableFromGPU(DrawablePtr drawable); + +Bool vncDRI3DrawInit(ScreenPtr screen); + +#endif + +#endif diff --git a/unix/xserver/hw/vnc/vncDRI3Draw.c b/unix/xserver/hw/vnc/vncDRI3Draw.c new file mode 100644 index 0000000000..8aa6625d37 --- /dev/null +++ b/unix/xserver/hw/vnc/vncDRI3Draw.c @@ -0,0 +1,785 @@ +/* Copyright 2024 Pierre Ossman for Cendio AB + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include "vncDRI3.h" + +#include +#include +#include + +static DevPrivateKeyRec vncDRI3DrawScreenPrivateKey; +static DevPrivateKeyRec vncDRI3GCPrivateKey; + +typedef struct vncDRI3DrawScreenPrivateRec { + CloseScreenProcPtr CloseScreen; + + CreateGCProcPtr CreateGC; + SourceValidateProcPtr SourceValidate; + + CompositeProcPtr Composite; + GlyphsProcPtr Glyphs; + CompositeRectsProcPtr CompositeRects; + TrapezoidsProcPtr Trapezoids; + TrianglesProcPtr Triangles; + TriStripProcPtr TriStrip; + TriFanProcPtr TriFan; +} vncDRI3DrawScreenPrivateRec, *vncDRI3DrawScreenPrivatePtr; + +typedef struct vncDRI3GCPrivateRec { + const GCFuncs *funcs; + const GCOps *ops; +} vncDRI3GCPrivateRec, *vncDRI3GCPrivatePtr; + +#define wrap(priv, real, mem, func) {\ + priv->mem = real->mem; \ + real->mem = func; \ +} + +#define unwrap(priv, real, mem) {\ + real->mem = priv->mem; \ +} + +static inline vncDRI3DrawScreenPrivatePtr vncDRI3DrawScreenPrivate(ScreenPtr screen) +{ + return (vncDRI3DrawScreenPrivatePtr)dixLookupPrivate(&(screen)->devPrivates, &vncDRI3DrawScreenPrivateKey); +} + +static inline vncDRI3GCPrivatePtr vncDRI3GCPrivate(GCPtr gc) +{ + return (vncDRI3GCPrivatePtr)dixLookupPrivate(&(gc)->devPrivates, &vncDRI3GCPrivateKey); +} + +static GCFuncs vncDRI3GCFuncs; +static GCOps vncDRI3GCOps; + +/* GC functions */ + +static void vncDRI3ValidateGC(GCPtr gc, unsigned long changes, + DrawablePtr drawable) +{ + vncDRI3GCPrivatePtr gcPriv = vncDRI3GCPrivate(gc); + + unwrap(gcPriv, gc, funcs); + if (gcPriv->ops != NULL) + unwrap(gcPriv, gc, ops); + + (*gc->funcs->ValidateGC)(gc, changes, drawable); + + if (vncDRI3IsHardwareDrawable(drawable)) { + wrap(gcPriv, gc, ops, &vncDRI3GCOps); + } else { + gcPriv->ops = NULL; + } + wrap(gcPriv, gc, funcs, &vncDRI3GCFuncs); +} + +static void vncDRI3ChangeGC(GCPtr gc, unsigned long mask) +{ + vncDRI3GCPrivatePtr gcPriv = vncDRI3GCPrivate(gc); + unwrap(gcPriv, gc, funcs); + if (gcPriv->ops != NULL) + unwrap(gcPriv, gc, ops); + (*gc->funcs->ChangeGC)(gc, mask); + if (gcPriv->ops != NULL) + wrap(gcPriv, gc, ops, &vncDRI3GCOps); + wrap(gcPriv, gc, funcs, &vncDRI3GCFuncs); +} + +static void vncDRI3CopyGC(GCPtr src, unsigned long mask, GCPtr dst) +{ + vncDRI3GCPrivatePtr gcPriv = vncDRI3GCPrivate(dst); + unwrap(gcPriv, dst, funcs); + if (gcPriv->ops != NULL) + unwrap(gcPriv, dst, ops); + (*dst->funcs->CopyGC)(src, mask, dst); + if (gcPriv->ops != NULL) + wrap(gcPriv, dst, ops, &vncDRI3GCOps); + wrap(gcPriv, dst, funcs, &vncDRI3GCFuncs); +} + +static void vncDRI3DestroyGC(GCPtr gc) +{ + vncDRI3GCPrivatePtr gcPriv = vncDRI3GCPrivate(gc); + unwrap(gcPriv, gc, funcs); + if (gcPriv->ops != NULL) + unwrap(gcPriv, gc, ops); + (*gc->funcs->DestroyGC)(gc); + if (gcPriv->ops != NULL) + wrap(gcPriv, gc, ops, &vncDRI3GCOps); + wrap(gcPriv, gc, funcs, &vncDRI3GCFuncs); +} + +static void vncDRI3ChangeClip(GCPtr gc, int type, void *value, int nrects) +{ + vncDRI3GCPrivatePtr gcPriv = vncDRI3GCPrivate(gc); + unwrap(gcPriv, gc, funcs); + if (gcPriv->ops != NULL) + unwrap(gcPriv, gc, ops); + (*gc->funcs->ChangeClip)(gc, type, value, nrects); + if (gcPriv->ops != NULL) + wrap(gcPriv, gc, ops, &vncDRI3GCOps); + wrap(gcPriv, gc, funcs, &vncDRI3GCFuncs); +} + +static void vncDRI3DestroyClip(GCPtr gc) +{ + vncDRI3GCPrivatePtr gcPriv = vncDRI3GCPrivate(gc); + unwrap(gcPriv, gc, funcs); + if (gcPriv->ops != NULL) + unwrap(gcPriv, gc, ops); + (*gc->funcs->DestroyClip)(gc); + if (gcPriv->ops != NULL) + wrap(gcPriv, gc, ops, &vncDRI3GCOps); + wrap(gcPriv, gc, funcs, &vncDRI3GCFuncs); +} + +static void vncDRI3CopyClip(GCPtr dst, GCPtr src) +{ + vncDRI3GCPrivatePtr gcPriv = vncDRI3GCPrivate(dst); + unwrap(gcPriv, dst, funcs); + if (gcPriv->ops != NULL) + unwrap(gcPriv, dst, ops); + (*dst->funcs->CopyClip)(dst, src); + if (gcPriv->ops != NULL) + wrap(gcPriv, dst, ops, &vncDRI3GCOps); + wrap(gcPriv, dst, funcs, &vncDRI3GCFuncs); +} + +/* GC operations */ + +static void vncDRI3FillSpans(DrawablePtr drawable, GCPtr gc, int nInit, + DDXPointPtr pptInit, int *pwidthInit, + int fSorted) +{ + vncDRI3GCPrivatePtr gcPriv = vncDRI3GCPrivate(gc); + + /* FIXME: Compute what we need to sync */ + vncDRI3SyncDrawableFromGPU(drawable); + + unwrap(gcPriv, gc, funcs); + unwrap(gcPriv, gc, ops); + (*gc->ops->FillSpans)(drawable, gc, nInit, pptInit, pwidthInit, fSorted); + wrap(gcPriv, gc, ops, &vncDRI3GCOps); + wrap(gcPriv, gc, funcs, &vncDRI3GCFuncs); + + vncDRI3SyncDrawableToGPU(drawable); +} + +static void vncDRI3SetSpans(DrawablePtr drawable, GCPtr gc, char *psrc, + DDXPointPtr ppt, int *pwidth, int nspans, + int fSorted) +{ + vncDRI3GCPrivatePtr gcPriv = vncDRI3GCPrivate(gc); + + /* FIXME: Compute what we need to sync */ + vncDRI3SyncDrawableFromGPU(drawable); + + unwrap(gcPriv, gc, funcs); + unwrap(gcPriv, gc, ops); + (*gc->ops->SetSpans)(drawable, gc, psrc, ppt, pwidth, nspans, fSorted); + wrap(gcPriv, gc, ops, &vncDRI3GCOps); + wrap(gcPriv, gc, funcs, &vncDRI3GCFuncs); + + vncDRI3SyncDrawableToGPU(drawable); +} + +static void vncDRI3PutImage(DrawablePtr drawable, GCPtr gc, int depth, + int x, int y, int w, int h, int leftPad, + int format, char *pBits) +{ + vncDRI3GCPrivatePtr gcPriv = vncDRI3GCPrivate(gc); + + /* FIXME: Compute what we need to sync */ + vncDRI3SyncDrawableFromGPU(drawable); + + unwrap(gcPriv, gc, funcs); + unwrap(gcPriv, gc, ops); + (*gc->ops->PutImage)(drawable, gc, depth, x, y, w, h, leftPad, format, pBits); + wrap(gcPriv, gc, ops, &vncDRI3GCOps); + wrap(gcPriv, gc, funcs, &vncDRI3GCFuncs); + + vncDRI3SyncDrawableToGPU(drawable); +} + +static RegionPtr vncDRI3CopyArea(DrawablePtr src, DrawablePtr dst, + GCPtr gc, int srcx, int srcy, + int w, int h, int dstx, int dsty) +{ + vncDRI3GCPrivatePtr gcPriv = vncDRI3GCPrivate(gc); + RegionPtr ret; + + /* FIXME: Compute what we need to sync */ + vncDRI3SyncDrawableFromGPU(dst); + + unwrap(gcPriv, gc, funcs); + unwrap(gcPriv, gc, ops); + ret = (*gc->ops->CopyArea)(src, dst, gc, srcx, srcy, w, h, dstx, dsty); + wrap(gcPriv, gc, ops, &vncDRI3GCOps); + wrap(gcPriv, gc, funcs, &vncDRI3GCFuncs); + + vncDRI3SyncDrawableToGPU(dst); + + return ret; +} + +static RegionPtr vncDRI3CopyPlane(DrawablePtr src, DrawablePtr dst, + GCPtr gc, int srcx, int srcy, + int w, int h, int dstx, int dsty, + unsigned long plane) +{ + vncDRI3GCPrivatePtr gcPriv = vncDRI3GCPrivate(gc); + RegionPtr ret; + + /* FIXME: Compute what we need to sync */ + vncDRI3SyncDrawableFromGPU(dst); + + unwrap(gcPriv, gc, funcs); + unwrap(gcPriv, gc, ops); + ret = (*gc->ops->CopyPlane)(src, dst, gc, srcx, srcy, w, h, dstx, dsty, plane); + wrap(gcPriv, gc, ops, &vncDRI3GCOps); + wrap(gcPriv, gc, funcs, &vncDRI3GCFuncs); + + vncDRI3SyncDrawableToGPU(dst); + + return ret; +} + +static void vncDRI3PolyPoint(DrawablePtr drawable, GCPtr gc, int mode, + int npt, xPoint *pts) +{ + vncDRI3GCPrivatePtr gcPriv = vncDRI3GCPrivate(gc); + + /* FIXME: Compute what we need to sync */ + vncDRI3SyncDrawableFromGPU(drawable); + + unwrap(gcPriv, gc, funcs); + unwrap(gcPriv, gc, ops); + (*gc->ops->PolyPoint)(drawable, gc, mode, npt, pts); + wrap(gcPriv, gc, ops, &vncDRI3GCOps); + wrap(gcPriv, gc, funcs, &vncDRI3GCFuncs); + + vncDRI3SyncDrawableToGPU(drawable); +} + +static void vncDRI3Polylines(DrawablePtr drawable, GCPtr gc, int mode, + int npt, DDXPointPtr ppts) +{ + vncDRI3GCPrivatePtr gcPriv = vncDRI3GCPrivate(gc); + + /* FIXME: Compute what we need to sync */ + vncDRI3SyncDrawableFromGPU(drawable); + + unwrap(gcPriv, gc, funcs); + unwrap(gcPriv, gc, ops); + (*gc->ops->Polylines)(drawable, gc, mode, npt, ppts); + wrap(gcPriv, gc, ops, &vncDRI3GCOps); + wrap(gcPriv, gc, funcs, &vncDRI3GCFuncs); + + vncDRI3SyncDrawableToGPU(drawable); +} + +static void vncDRI3PolySegment(DrawablePtr drawable, GCPtr gc, int nseg, + xSegment *segs) +{ + vncDRI3GCPrivatePtr gcPriv = vncDRI3GCPrivate(gc); + + /* FIXME: Compute what we need to sync */ + vncDRI3SyncDrawableFromGPU(drawable); + + unwrap(gcPriv, gc, funcs); + unwrap(gcPriv, gc, ops); + (*gc->ops->PolySegment)(drawable, gc, nseg, segs); + wrap(gcPriv, gc, ops, &vncDRI3GCOps); + wrap(gcPriv, gc, funcs, &vncDRI3GCFuncs); + + vncDRI3SyncDrawableToGPU(drawable); +} + +static void vncDRI3PolyRectangle(DrawablePtr drawable, GCPtr gc, + int nrects, xRectangle *rects) +{ + vncDRI3GCPrivatePtr gcPriv = vncDRI3GCPrivate(gc); + + /* FIXME: Compute what we need to sync */ + vncDRI3SyncDrawableFromGPU(drawable); + + unwrap(gcPriv, gc, funcs); + unwrap(gcPriv, gc, ops); + (*gc->ops->PolyRectangle)(drawable, gc, nrects, rects); + wrap(gcPriv, gc, ops, &vncDRI3GCOps); + wrap(gcPriv, gc, funcs, &vncDRI3GCFuncs); + + vncDRI3SyncDrawableToGPU(drawable); +} + +static void vncDRI3PolyArc(DrawablePtr drawable, GCPtr gc, int narcs, + xArc *arcs) +{ + vncDRI3GCPrivatePtr gcPriv = vncDRI3GCPrivate(gc); + + /* FIXME: Compute what we need to sync */ + vncDRI3SyncDrawableFromGPU(drawable); + + unwrap(gcPriv, gc, funcs); + unwrap(gcPriv, gc, ops); + (*gc->ops->PolyArc)(drawable, gc, narcs, arcs); + wrap(gcPriv, gc, ops, &vncDRI3GCOps); + wrap(gcPriv, gc, funcs, &vncDRI3GCFuncs); + + vncDRI3SyncDrawableToGPU(drawable); +} + +static void vncDRI3FillPolygon(DrawablePtr drawable, GCPtr gc, + int shape, int mode, int count, + DDXPointPtr pts) +{ + vncDRI3GCPrivatePtr gcPriv = vncDRI3GCPrivate(gc); + + /* FIXME: Compute what we need to sync */ + vncDRI3SyncDrawableFromGPU(drawable); + + unwrap(gcPriv, gc, funcs); + unwrap(gcPriv, gc, ops); + (*gc->ops->FillPolygon)(drawable, gc, shape, mode, count, pts); + wrap(gcPriv, gc, ops, &vncDRI3GCOps); + wrap(gcPriv, gc, funcs, &vncDRI3GCFuncs); + + vncDRI3SyncDrawableToGPU(drawable); +} + +static void vncDRI3PolyFillRect(DrawablePtr drawable, GCPtr gc, + int nrects, xRectangle *rects) +{ + vncDRI3GCPrivatePtr gcPriv = vncDRI3GCPrivate(gc); + + /* FIXME: Compute what we need to sync */ + vncDRI3SyncDrawableFromGPU(drawable); + + unwrap(gcPriv, gc, funcs); + unwrap(gcPriv, gc, ops); + (*gc->ops->PolyFillRect)(drawable, gc, nrects, rects); + wrap(gcPriv, gc, ops, &vncDRI3GCOps); + wrap(gcPriv, gc, funcs, &vncDRI3GCFuncs); + + vncDRI3SyncDrawableToGPU(drawable); +} + +static void vncDRI3PolyFillArc(DrawablePtr drawable, GCPtr gc, + int narcs, xArc *arcs) +{ + vncDRI3GCPrivatePtr gcPriv = vncDRI3GCPrivate(gc); + + /* FIXME: Compute what we need to sync */ + vncDRI3SyncDrawableFromGPU(drawable); + + unwrap(gcPriv, gc, funcs); + unwrap(gcPriv, gc, ops); + (*gc->ops->PolyFillArc)(drawable, gc, narcs, arcs); + wrap(gcPriv, gc, ops, &vncDRI3GCOps); + wrap(gcPriv, gc, funcs, &vncDRI3GCFuncs); + + vncDRI3SyncDrawableToGPU(drawable); +} + +static int vncDRI3PolyText8(DrawablePtr drawable, GCPtr gc, + int x, int y, int count, char *chars) +{ + vncDRI3GCPrivatePtr gcPriv = vncDRI3GCPrivate(gc); + int ret; + + /* FIXME: Compute what we need to sync */ + vncDRI3SyncDrawableFromGPU(drawable); + + unwrap(gcPriv, gc, funcs); + unwrap(gcPriv, gc, ops); + ret = (*gc->ops->PolyText8)(drawable, gc, x, y, count, chars); + wrap(gcPriv, gc, ops, &vncDRI3GCOps); + wrap(gcPriv, gc, funcs, &vncDRI3GCFuncs); + + vncDRI3SyncDrawableToGPU(drawable); + + return ret; +} + +static int vncDRI3PolyText16(DrawablePtr drawable, GCPtr gc, + int x, int y, int count, + unsigned short *chars) +{ + vncDRI3GCPrivatePtr gcPriv = vncDRI3GCPrivate(gc); + int ret; + + /* FIXME: Compute what we need to sync */ + vncDRI3SyncDrawableFromGPU(drawable); + + unwrap(gcPriv, gc, funcs); + unwrap(gcPriv, gc, ops); + ret = (*gc->ops->PolyText16)(drawable, gc, x, y, count, chars); + wrap(gcPriv, gc, ops, &vncDRI3GCOps); + wrap(gcPriv, gc, funcs, &vncDRI3GCFuncs); + + vncDRI3SyncDrawableToGPU(drawable); + + return ret; +} + +static void vncDRI3ImageText8(DrawablePtr drawable, GCPtr gc, + int x, int y, int count, char *chars) +{ + vncDRI3GCPrivatePtr gcPriv = vncDRI3GCPrivate(gc); + + /* FIXME: Compute what we need to sync */ + vncDRI3SyncDrawableFromGPU(drawable); + + unwrap(gcPriv, gc, funcs); + unwrap(gcPriv, gc, ops); + (*gc->ops->ImageText8)(drawable, gc, x, y, count, chars); + wrap(gcPriv, gc, ops, &vncDRI3GCOps); + wrap(gcPriv, gc, funcs, &vncDRI3GCFuncs); + + vncDRI3SyncDrawableToGPU(drawable); +} + +static void vncDRI3ImageText16(DrawablePtr drawable, GCPtr gc, + int x, int y, int count, + unsigned short *chars) +{ + vncDRI3GCPrivatePtr gcPriv = vncDRI3GCPrivate(gc); + + /* FIXME: Compute what we need to sync */ + vncDRI3SyncDrawableFromGPU(drawable); + + unwrap(gcPriv, gc, funcs); + unwrap(gcPriv, gc, ops); + (*gc->ops->ImageText16)(drawable, gc, x, y, count, chars); + wrap(gcPriv, gc, ops, &vncDRI3GCOps); + wrap(gcPriv, gc, funcs, &vncDRI3GCFuncs); + + vncDRI3SyncDrawableToGPU(drawable); +} + +static void vncDRI3ImageGlyphBlt(DrawablePtr drawable, GCPtr gc, int x, + int y, unsigned int nglyph, + CharInfoPtr *ppci, void * pglyphBase) +{ + vncDRI3GCPrivatePtr gcPriv = vncDRI3GCPrivate(gc); + + /* FIXME: Compute what we need to sync */ + vncDRI3SyncDrawableFromGPU(drawable); + + unwrap(gcPriv, gc, funcs); + unwrap(gcPriv, gc, ops); + (*gc->ops->ImageGlyphBlt)(drawable, gc, x, y, nglyph, ppci, pglyphBase); + wrap(gcPriv, gc, ops, &vncDRI3GCOps); + wrap(gcPriv, gc, funcs, &vncDRI3GCFuncs); + + vncDRI3SyncDrawableToGPU(drawable); +} + +static void vncDRI3PolyGlyphBlt(DrawablePtr drawable, GCPtr gc, int x, + int y, unsigned int nglyph, + CharInfoPtr *ppci, void * pglyphBase) +{ + vncDRI3GCPrivatePtr gcPriv = vncDRI3GCPrivate(gc); + + /* FIXME: Compute what we need to sync */ + vncDRI3SyncDrawableFromGPU(drawable); + + unwrap(gcPriv, gc, funcs); + unwrap(gcPriv, gc, ops); + (*gc->ops->PolyGlyphBlt)(drawable, gc, x, y, nglyph, ppci, pglyphBase); + wrap(gcPriv, gc, ops, &vncDRI3GCOps); + wrap(gcPriv, gc, funcs, &vncDRI3GCFuncs); + + vncDRI3SyncDrawableToGPU(drawable); +} + +static void vncDRI3PushPixels(GCPtr gc, PixmapPtr pBitMap, + DrawablePtr drawable, + int w, int h, int x, int y) +{ + vncDRI3GCPrivatePtr gcPriv = vncDRI3GCPrivate(gc); + + /* FIXME: Compute what we need to sync */ + vncDRI3SyncDrawableFromGPU(drawable); + + unwrap(gcPriv, gc, funcs); + unwrap(gcPriv, gc, ops); + (*gc->ops->PushPixels)(gc, pBitMap, drawable, w, h, x, y); + wrap(gcPriv, gc, ops, &vncDRI3GCOps); + wrap(gcPriv, gc, funcs, &vncDRI3GCFuncs); + + vncDRI3SyncDrawableToGPU(drawable); +} + +static GCFuncs vncDRI3GCFuncs = { + .ValidateGC = vncDRI3ValidateGC, + .ChangeGC = vncDRI3ChangeGC, + .CopyGC = vncDRI3CopyGC, + .DestroyGC = vncDRI3DestroyGC, + .ChangeClip = vncDRI3ChangeClip, + .DestroyClip = vncDRI3DestroyClip, + .CopyClip = vncDRI3CopyClip, +}; + +static GCOps vncDRI3GCOps = { + .FillSpans = vncDRI3FillSpans, + .SetSpans = vncDRI3SetSpans, + .PutImage = vncDRI3PutImage, + .CopyArea = vncDRI3CopyArea, + .CopyPlane = vncDRI3CopyPlane, + .PolyPoint = vncDRI3PolyPoint, + .Polylines = vncDRI3Polylines, + .PolySegment = vncDRI3PolySegment, + .PolyRectangle = vncDRI3PolyRectangle, + .PolyArc = vncDRI3PolyArc, + .FillPolygon = vncDRI3FillPolygon, + .PolyFillRect = vncDRI3PolyFillRect, + .PolyFillArc = vncDRI3PolyFillArc, + .PolyText8 = vncDRI3PolyText8, + .PolyText16 = vncDRI3PolyText16, + .ImageText8 = vncDRI3ImageText8, + .ImageText16 = vncDRI3ImageText16, + .ImageGlyphBlt = vncDRI3ImageGlyphBlt, + .PolyGlyphBlt = vncDRI3PolyGlyphBlt, + .PushPixels = vncDRI3PushPixels, +}; + +static Bool vncDRI3CreateGC(GCPtr gc) +{ + ScreenPtr screen = gc->pScreen; + vncDRI3DrawScreenPrivatePtr screenPriv = vncDRI3DrawScreenPrivate(screen); + vncDRI3GCPrivatePtr gcPriv; + Bool ret; + + unwrap(screenPriv, screen, CreateGC); + ret = (*screen->CreateGC)(gc); + wrap(screenPriv, screen, CreateGC, vncDRI3CreateGC); + + gcPriv = vncDRI3GCPrivate(gc); + + wrap(gcPriv, gc, funcs, &vncDRI3GCFuncs); + + return ret; +} + +static void vncDRI3SourceValidate(DrawablePtr drawable, + int x, int y, + int width, int height, + unsigned int subWindowMode) +{ + ScreenPtr screen = drawable->pScreen; + vncDRI3DrawScreenPrivatePtr screenPriv = vncDRI3DrawScreenPrivate(screen); + + /* FIXME: Compute what we need to sync */ + vncDRI3SyncDrawableFromGPU(drawable); + + unwrap(screenPriv, screen, SourceValidate); + screen->SourceValidate(drawable, x, y, width, height, subWindowMode); + wrap(screenPriv, screen, SourceValidate, vncDRI3SourceValidate); +} + +static void vncDRI3Composite(CARD8 op, PicturePtr pSrc, + PicturePtr pMask, PicturePtr pDst, + INT16 xSrc, INT16 ySrc, INT16 xMask, + INT16 yMask, INT16 xDst, INT16 yDst, + CARD16 width, CARD16 height) +{ + ScreenPtr screen = pDst->pDrawable->pScreen; + PictureScreenPtr ps = GetPictureScreen(screen); + vncDRI3DrawScreenPrivatePtr screenPriv = vncDRI3DrawScreenPrivate(screen); + + vncDRI3SyncDrawableFromGPU(pDst->pDrawable); + + unwrap(screenPriv, ps, Composite); + (*ps->Composite)(op, pSrc, pMask, pDst, xSrc, ySrc, + xMask, yMask, xDst, yDst, width, height); + wrap(screenPriv, ps, Composite, vncDRI3Composite); + + vncDRI3SyncDrawableToGPU(pDst->pDrawable); +} + +static void vncDRI3Glyphs(CARD8 op, PicturePtr pSrc, PicturePtr pDst, + PictFormatPtr maskFormat, + INT16 xSrc, INT16 ySrc, int nlists, + GlyphListPtr lists, GlyphPtr * glyphs) +{ + ScreenPtr screen = pDst->pDrawable->pScreen; + PictureScreenPtr ps = GetPictureScreen(screen); + vncDRI3DrawScreenPrivatePtr screenPriv = vncDRI3DrawScreenPrivate(screen); + + vncDRI3SyncDrawableFromGPU(pDst->pDrawable); + + unwrap(screenPriv, ps, Glyphs); + (*ps->Glyphs)(op, pSrc, pDst, maskFormat, xSrc, ySrc, + nlists, lists, glyphs); + wrap(screenPriv, ps, Glyphs, vncDRI3Glyphs); + + vncDRI3SyncDrawableToGPU(pDst->pDrawable); +} + +static void vncDRI3CompositeRects(CARD8 op, PicturePtr pDst, + xRenderColor * color, int nRect, xRectangle *rects) +{ + ScreenPtr screen = pDst->pDrawable->pScreen; + PictureScreenPtr ps = GetPictureScreen(screen); + vncDRI3DrawScreenPrivatePtr screenPriv = vncDRI3DrawScreenPrivate(screen); + + vncDRI3SyncDrawableFromGPU(pDst->pDrawable); + + unwrap(screenPriv, ps, CompositeRects); + (*ps->CompositeRects)(op, pDst, color, nRect, rects); + wrap(screenPriv, ps, CompositeRects, vncDRI3CompositeRects); + + vncDRI3SyncDrawableToGPU(pDst->pDrawable); +} + +static void vncDRI3Trapezoids(CARD8 op, PicturePtr pSrc, PicturePtr pDst, + PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, + int ntrap, xTrapezoid * traps) +{ + ScreenPtr screen = pDst->pDrawable->pScreen; + PictureScreenPtr ps = GetPictureScreen(screen); + vncDRI3DrawScreenPrivatePtr screenPriv = vncDRI3DrawScreenPrivate(screen); + + /* FIXME: Rarely used, so we just sync everything */ + vncDRI3SyncDrawableFromGPU(pDst->pDrawable); + + unwrap(screenPriv, ps, Trapezoids); + (*ps->Trapezoids)(op, pSrc, pDst, maskFormat, xSrc, ySrc, + ntrap, traps); + wrap(screenPriv, ps, Trapezoids, vncDRI3Trapezoids); + + vncDRI3SyncDrawableToGPU(pDst->pDrawable); +} + +static void vncDRI3Triangles(CARD8 op, PicturePtr pSrc, PicturePtr pDst, + PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, + int ntri, xTriangle * tris) +{ + ScreenPtr screen = pDst->pDrawable->pScreen; + PictureScreenPtr ps = GetPictureScreen(screen); + vncDRI3DrawScreenPrivatePtr screenPriv = vncDRI3DrawScreenPrivate(screen); + + /* FIXME: Rarely used, so we just sync everything */ + vncDRI3SyncDrawableFromGPU(pDst->pDrawable); + + unwrap(screenPriv, ps, Triangles); + (*ps->Triangles)(op, pSrc, pDst, maskFormat, xSrc, ySrc, ntri, tris); + wrap(screenPriv, ps, Triangles, vncDRI3Triangles); + + vncDRI3SyncDrawableToGPU(pDst->pDrawable); +} + +static void vncDRI3TriStrip(CARD8 op, PicturePtr pSrc, PicturePtr pDst, + PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, + int npoint, xPointFixed * points) +{ + ScreenPtr screen = pDst->pDrawable->pScreen; + PictureScreenPtr ps = GetPictureScreen(screen); + vncDRI3DrawScreenPrivatePtr screenPriv = vncDRI3DrawScreenPrivate(screen); + + /* FIXME: Rarely used, so we just sync everything */ + vncDRI3SyncDrawableFromGPU(pDst->pDrawable); + + unwrap(screenPriv, ps, TriStrip); + (*ps->TriStrip)(op, pSrc, pDst, maskFormat, xSrc, ySrc, + npoint, points); + wrap(screenPriv, ps, TriStrip, vncDRI3TriStrip) + + vncDRI3SyncDrawableToGPU(pDst->pDrawable); +} + +static void vncDRI3TriFan(CARD8 op, PicturePtr pSrc, PicturePtr pDst, + PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, + int npoint, xPointFixed * points) +{ + ScreenPtr screen = pDst->pDrawable->pScreen; + PictureScreenPtr ps = GetPictureScreen(screen); + vncDRI3DrawScreenPrivatePtr screenPriv = vncDRI3DrawScreenPrivate(screen); + + /* FIXME: Rarely used, so we just sync everything */ + vncDRI3SyncDrawableFromGPU(pDst->pDrawable); + + unwrap(screenPriv, ps, TriFan); + (*ps->TriFan)(op, pSrc, pDst, maskFormat, xSrc, ySrc, npoint, points); + wrap(screenPriv, ps, TriFan, vncDRI3TriFan); + + vncDRI3SyncDrawableToGPU(pDst->pDrawable); +} + +static Bool vncDRI3DrawCloseScreen(ScreenPtr screen) +{ + vncDRI3DrawScreenPrivatePtr screenPriv = vncDRI3DrawScreenPrivate(screen); + PictureScreenPtr ps; + + unwrap(screenPriv, screen, CloseScreen); + + unwrap(screenPriv, screen, CreateGC); + unwrap(screenPriv, screen, SourceValidate); + + ps = GetPictureScreenIfSet(screen); + if (ps) { + unwrap(screenPriv, ps, Composite); + unwrap(screenPriv, ps, Glyphs); + unwrap(screenPriv, ps, CompositeRects); + unwrap(screenPriv, ps, Trapezoids); + unwrap(screenPriv, ps, Triangles); + unwrap(screenPriv, ps, TriStrip); + unwrap(screenPriv, ps, TriFan); + } + + return (*screen->CloseScreen)(screen); +} + +Bool vncDRI3DrawInit(ScreenPtr screen) +{ + vncDRI3DrawScreenPrivatePtr screenPriv; + PictureScreenPtr ps; + + if (!dixRegisterPrivateKey(&vncDRI3DrawScreenPrivateKey, + PRIVATE_SCREEN, + sizeof(vncDRI3DrawScreenPrivateRec))) + return FALSE; + if (!dixRegisterPrivateKey(&vncDRI3GCPrivateKey, PRIVATE_GC, + sizeof(vncDRI3GCPrivateRec))) + return FALSE; + + screenPriv = vncDRI3DrawScreenPrivate(screen); + + wrap(screenPriv, screen, CloseScreen, vncDRI3DrawCloseScreen); + + wrap(screenPriv, screen, CreateGC, vncDRI3CreateGC); + wrap(screenPriv, screen, SourceValidate, vncDRI3SourceValidate); + + ps = GetPictureScreenIfSet(screen); + if (ps) { + wrap(screenPriv, ps, Composite, vncDRI3Composite); + wrap(screenPriv, ps, Glyphs, vncDRI3Glyphs); + wrap(screenPriv, ps, CompositeRects, vncDRI3CompositeRects); + wrap(screenPriv, ps, Trapezoids, vncDRI3Trapezoids); + wrap(screenPriv, ps, Triangles, vncDRI3Triangles); + wrap(screenPriv, ps, TriStrip, vncDRI3TriStrip); + wrap(screenPriv, ps, TriFan, vncDRI3TriFan); + } + + return TRUE; +} \ No newline at end of file diff --git a/unix/xserver/hw/vnc/xvnc.c b/unix/xserver/hw/vnc/xvnc.c index 4ee1cd1b52..b77f469a11 100644 --- a/unix/xserver/hw/vnc/xvnc.c +++ b/unix/xserver/hw/vnc/xvnc.c @@ -36,6 +36,7 @@ from the X Consortium. #include "RFBGlue.h" #include "XorgGlue.h" #include "RandrGlue.h" +#include "vncDRI3.h" #include "vncPresent.h" #include "xorg-version.h" @@ -1088,6 +1089,12 @@ vncScreenInit(ScreenPtr pScreen, int argc, char **argv) if (!ret) ErrorF("Failed to initialize Present extension\n"); +#ifdef DRI3 + ret = vncDRI3Init(pScreen); + if (!ret) + ErrorF("Failed to initialize DRI3 extension\n"); +#endif + return TRUE; } /* end vncScreenInit */ diff --git a/unix/xserver120.patch b/unix/xserver120.patch index 82546dc9e1..9bc51822ab 100644 --- a/unix/xserver120.patch +++ b/unix/xserver120.patch @@ -1,7 +1,7 @@ -Index: xserver/configure.ac -=================================================================== ---- xserver.orig/configure.ac -+++ xserver/configure.ac +diff --git a/configure.ac b/configure.ac +index 0909cc5b4..c01873200 100644 +--- a/configure.ac ++++ b/configure.ac @@ -74,6 +74,7 @@ dnl forcing an entire recompile.x AC_CONFIG_HEADERS(include/version-config.h) @@ -10,17 +10,30 @@ Index: xserver/configure.ac AC_PROG_LN_S LT_PREREQ([2.2]) LT_INIT([disable-static win32-dll]) -@@ -1777,6 +1778,9 @@ if test "x$XVFB" = xyes; then +@@ -1735,6 +1736,14 @@ if test "x$XVFB" = xyes; then AC_SUBST([XVFB_SYS_LIBS]) fi +dnl Xvnc DDX +AC_SUBST([XVNC_LIBS], ["$FB_LIB $FIXES_LIB $XEXT_LIB $CONFIG_LIB $DBE_LIB $RECORD_LIB $GLX_LIBS $RANDR_LIB $RENDER_LIB $DAMAGE_LIB $DRI3_LIB $PRESENT_LIB $MIEXT_SYNC_LIB $MIEXT_DAMAGE_LIB $MIEXT_SHADOW_LIB $XI_LIB $XKB_LIB $XKB_STUB_LIB $COMPOSITE_LIB $MAIN_LIB"]) +AC_SUBST([XVNC_SYS_LIBS], ["$GLX_SYS_LIBS"]) ++ ++PKG_CHECK_MODULES(GBM, "$LIBGBM", [GBM=yes], [GBM=no]) ++if test "x$GBM" = xyes; then ++ AC_DEFINE(HAVE_GBM, 1, [Have GBM support]) ++fi dnl Xnest DDX -@@ -2565,6 +2571,7 @@ hw/dmx/Makefile +@@ -2058,7 +2067,6 @@ if test "x$GLAMOR" = xyes; then + [AC_DEFINE(GLAMOR_HAS_EGL_QUERY_DRIVER, 1, [Have GLAMOR_HAS_EGL_QUERY_DRIVER])], + []) + +- PKG_CHECK_MODULES(GBM, "$LIBGBM", [GBM=yes], [GBM=no]) + if test "x$GBM" = xyes; then + AC_DEFINE(GLAMOR_HAS_GBM, 1, + [Build glamor with GBM-based EGL support]) +@@ -2523,6 +2531,7 @@ hw/dmx/Makefile hw/dmx/man/Makefile hw/vfb/Makefile hw/vfb/man/Makefile @@ -28,10 +41,10 @@ Index: xserver/configure.ac hw/xnest/Makefile hw/xnest/man/Makefile hw/xwin/Makefile -Index: xserver/dri3/Makefile.am -=================================================================== ---- xserver.orig/dri3/Makefile.am -+++ xserver/dri3/Makefile.am +diff --git a/dri3/Makefile.am b/dri3/Makefile.am +index e47a734e0..99c3718a5 100644 +--- a/dri3/Makefile.am ++++ b/dri3/Makefile.am @@ -1,7 +1,7 @@ noinst_LTLIBRARIES = libdri3.la AM_CFLAGS = \ @@ -42,10 +55,10 @@ Index: xserver/dri3/Makefile.am libdri3_la_SOURCES = \ dri3.h \ -Index: xserver/dri3/dri3.c -=================================================================== ---- xserver.orig/dri3/dri3.c -+++ xserver/dri3/dri3.c +diff --git a/dri3/dri3.c b/dri3/dri3.c +index ba32facd7..191252969 100644 +--- a/dri3/dri3.c ++++ b/dri3/dri3.c @@ -20,10 +20,6 @@ * OF THIS SOFTWARE. */ @@ -57,10 +70,10 @@ Index: xserver/dri3/dri3.c #include "dri3_priv.h" #include -Index: xserver/dri3/dri3_priv.h -=================================================================== ---- xserver.orig/dri3/dri3_priv.h -+++ xserver/dri3/dri3_priv.h +diff --git a/dri3/dri3_priv.h b/dri3/dri3_priv.h +index b087a9529..f319d1770 100644 +--- a/dri3/dri3_priv.h ++++ b/dri3/dri3_priv.h @@ -23,6 +23,7 @@ #ifndef _DRI3PRIV_H_ #define _DRI3PRIV_H_ @@ -69,10 +82,10 @@ Index: xserver/dri3/dri3_priv.h #include #include "scrnintstr.h" #include "misc.h" -Index: xserver/dri3/dri3_request.c -=================================================================== ---- xserver.orig/dri3/dri3_request.c -+++ xserver/dri3/dri3_request.c +diff --git a/dri3/dri3_request.c b/dri3/dri3_request.c +index 958877efa..687168930 100644 +--- a/dri3/dri3_request.c ++++ b/dri3/dri3_request.c @@ -20,10 +20,6 @@ * OF THIS SOFTWARE. */ @@ -84,10 +97,10 @@ Index: xserver/dri3/dri3_request.c #include "dri3_priv.h" #include #include -Index: xserver/dri3/dri3_screen.c -=================================================================== ---- xserver.orig/dri3/dri3_screen.c -+++ xserver/dri3/dri3_screen.c +diff --git a/dri3/dri3_screen.c b/dri3/dri3_screen.c +index b98259753..3c7e5bf60 100644 +--- a/dri3/dri3_screen.c ++++ b/dri3/dri3_screen.c @@ -20,10 +20,6 @@ * OF THIS SOFTWARE. */ @@ -99,17 +112,27 @@ Index: xserver/dri3/dri3_screen.c #include "dri3_priv.h" #include #include -Index: xserver/hw/Makefile.am -=================================================================== ---- xserver.orig/hw/Makefile.am -+++ xserver/hw/Makefile.am -@@ -38,7 +38,8 @@ SUBDIRS = \ - $(DMX_SUBDIRS) \ - $(KDRIVE_SUBDIRS) \ - $(XQUARTZ_SUBDIRS) \ -- $(XWAYLAND_SUBDIRS) -+ $(XWAYLAND_SUBDIRS) \ -+ vnc +diff --git a/hw/Makefile.am b/hw/Makefile.am +index 19895dc77..3ecfa8b7a 100644 +--- a/hw/Makefile.am ++++ b/hw/Makefile.am +@@ -44,3 +44,5 @@ DIST_SUBDIRS = dmx xfree86 vfb xnest xwin xquartz kdrive xwayland + + relink: + $(AM_V_at)for i in $(SUBDIRS) ; do $(MAKE) -C $$i relink || exit 1 ; done ++ ++SUBDIRS += vnc +diff --git a/include/dix-config.h.in b/include/dix-config.h.in +index f8fc67067..d53c4e72f 100644 +--- a/include/dix-config.h.in ++++ b/include/dix-config.h.in +@@ -83,6 +83,9 @@ + /* Define to 1 if you have the header file. */ + #undef HAVE_FCNTL_H - DIST_SUBDIRS = dmx xfree86 vfb xnest xwin xquartz kdrive xwayland ++/* Have GBM support */ ++#undef HAVE_GBM ++ + /* Define to 1 if you have the `getdtablesize' function. */ + #undef HAVE_GETDTABLESIZE diff --git a/unix/xserver21.1.1.patch b/unix/xserver21.1.1.patch deleted file mode 100644 index 3fbaae5181..0000000000 --- a/unix/xserver21.1.1.patch +++ /dev/null @@ -1,38 +0,0 @@ -diff -urpN xorg-server-1.20.0/configure.ac xorg-server-1.20.0/configure.ac ---- xorg-server-1.20.0/configure.ac 2018-05-10 09:32:34.000000000 -0700 -+++ xorg-server-1.20.0/configure.ac 2018-06-13 19:04:47.536413626 -0700 -@@ -74,6 +74,7 @@ dnl forcing an entire recompile.x - AC_CONFIG_HEADERS(include/version-config.h) - - AM_PROG_AS -+AC_PROG_CXX - AC_PROG_LN_S - LT_PREREQ([2.2]) - LT_INIT([disable-static win32-dll]) -@@ -1777,6 +1778,9 @@ if test "x$XVFB" = xyes; then - AC_SUBST([XVFB_SYS_LIBS]) - fi - -+dnl Xvnc DDX -+AC_SUBST([XVNC_LIBS], ["$FB_LIB $FIXES_LIB $XEXT_LIB $CONFIG_LIB $DBE_LIB $RECORD_LIB $GLX_LIBS $RANDR_LIB $RENDER_LIB $DAMAGE_LIB $DRI3_LIB $PRESENT_LIB $MIEXT_SYNC_LIB $MIEXT_DAMAGE_LIB $MIEXT_SHADOW_LIB $XI_LIB $XKB_LIB $XKB_STUB_LIB $COMPOSITE_LIB $MAIN_LIB"]) -+AC_SUBST([XVNC_SYS_LIBS], ["$GLX_SYS_LIBS"]) - - dnl Xnest DDX - -@@ -2565,6 +2571,7 @@ hw/dmx/Makefile - hw/dmx/man/Makefile - hw/vfb/Makefile - hw/vfb/man/Makefile -+hw/vnc/Makefile - hw/xnest/Makefile - hw/xnest/man/Makefile - hw/xwin/Makefile -diff -urpN xorg-server-1.20.0/hw/Makefile.am xorg-server-1.20.0/hw/Makefile.am ---- xorg-server-1.20.0/hw/Makefile.am 2018-05-10 09:32:34.000000000 -0700 -+++ xorg-server-1.20.0/hw/Makefile.am 2018-06-13 19:04:47.536413626 -0700 -@@ -44,3 +44,5 @@ - - relink: - $(AM_V_at)for i in $(SUBDIRS) ; do $(MAKE) -C $$i relink || exit 1 ; done -+ -+SUBDIRS += vnc diff --git a/unix/xserver21.patch b/unix/xserver21.patch new file mode 100644 index 0000000000..7f1e8d4f62 --- /dev/null +++ b/unix/xserver21.patch @@ -0,0 +1,67 @@ +diff --git a/configure.ac b/configure.ac +index fad7b5769..2c167de3d 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -72,6 +72,7 @@ dnl forcing an entire recompile.x + AC_CONFIG_HEADERS(include/version-config.h) + + AM_PROG_AS ++AC_PROG_CXX + AC_PROG_LN_S + LT_PREREQ([2.2]) + LT_INIT([disable-static win32-dll]) +@@ -1720,6 +1721,14 @@ if test "x$XVFB" = xyes; then + AC_SUBST([XVFB_SYS_LIBS]) + fi + ++dnl Xvnc DDX ++AC_SUBST([XVNC_LIBS], ["$FB_LIB $FIXES_LIB $XEXT_LIB $CONFIG_LIB $DBE_LIB $RECORD_LIB $GLX_LIBS $RANDR_LIB $RENDER_LIB $DAMAGE_LIB $DRI3_LIB $PRESENT_LIB $MIEXT_SYNC_LIB $MIEXT_DAMAGE_LIB $MIEXT_SHADOW_LIB $XI_LIB $XKB_LIB $XKB_STUB_LIB $COMPOSITE_LIB $MAIN_LIB"]) ++AC_SUBST([XVNC_SYS_LIBS], ["$GLX_SYS_LIBS"]) ++ ++PKG_CHECK_MODULES(GBM, "$LIBGBM", [GBM=yes], [GBM=no]) ++if test "x$GBM" = xyes; then ++ AC_DEFINE(HAVE_GBM, 1, [Have GBM support]) ++fi + + dnl Xnest DDX + +@@ -2038,7 +2047,6 @@ if test "x$GLAMOR" = xyes; then + [AC_DEFINE(GLAMOR_HAS_EGL_QUERY_DRIVER, 1, [Have GLAMOR_HAS_EGL_QUERY_DRIVER])], + []) + +- PKG_CHECK_MODULES(GBM, "$LIBGBM", [GBM=yes], [GBM=no]) + if test "x$GBM" = xyes; then + AC_DEFINE(GLAMOR_HAS_GBM, 1, + [Build glamor with GBM-based EGL support]) +@@ -2346,6 +2354,7 @@ hw/xfree86/utils/man/Makefile + hw/xfree86/utils/gtf/Makefile + hw/vfb/Makefile + hw/vfb/man/Makefile ++hw/vnc/Makefile + hw/xnest/Makefile + hw/xnest/man/Makefile + hw/xwin/Makefile +diff --git a/hw/Makefile.am b/hw/Makefile.am +index 1749018fa..1172cd59b 100644 +--- a/hw/Makefile.am ++++ b/hw/Makefile.am +@@ -34,3 +34,5 @@ DIST_SUBDIRS = xfree86 vfb xnest xwin xquartz kdrive + + relink: + $(AM_V_at)for i in $(SUBDIRS) ; do $(MAKE) -C $$i relink || exit 1 ; done ++ ++SUBDIRS += vnc +diff --git a/include/dix-config.h.in b/include/dix-config.h.in +index 382d70609..04a4fd263 100644 +--- a/include/dix-config.h.in ++++ b/include/dix-config.h.in +@@ -77,6 +77,9 @@ + /* Define to 1 if you have the header file. */ + #undef HAVE_FCNTL_H + ++/* Have GBM support */ ++#undef HAVE_GBM ++ + /* Define to 1 if you have the `getdtablesize' function. */ + #undef HAVE_GETDTABLESIZE + From d569c7599f04c33a771786279312fc3d66da2c86 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sat, 24 Feb 2024 14:02:02 +0100 Subject: [PATCH 4/6] Hide from GNOME to enable animations One GNOME developer had a bad experience with VNC one time, and therefore all VNC must forever be punished. Avoid detection by GNOME so that animations aren't forcefully disabled without any option for the user to re-enable them. --- unix/vncconfig/vncExt.h | 2 +- unix/xserver/hw/vnc/xvnc.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/unix/vncconfig/vncExt.h b/unix/vncconfig/vncExt.h index 2b24469e34..17f4fecc42 100644 --- a/unix/vncconfig/vncExt.h +++ b/unix/vncconfig/vncExt.h @@ -64,7 +64,7 @@ typedef struct { #ifdef _VNCEXT_PROTO_ -#define VNCEXTNAME "VNC-EXTENSION" +#define VNCEXTNAME "TIGERVNC" typedef struct { CARD8 reqType; /* always VncExtReqCode */ diff --git a/unix/xserver/hw/vnc/xvnc.c b/unix/xserver/hw/vnc/xvnc.c index b77f469a11..a441f82401 100644 --- a/unix/xserver/hw/vnc/xvnc.c +++ b/unix/xserver/hw/vnc/xvnc.c @@ -1117,7 +1117,7 @@ extern void GlxExtensionInit(void); #endif static const ExtensionModule vncExtensions[] = { - {vncExtensionInit, "VNC-EXTENSION", NULL}, + {vncExtensionInit, "TIGERVNC", NULL}, #ifdef GLXEXT #if XORG_OLDER_THAN(1, 20, 0) { GlxExtensionInit, "GLX", &noGlxExtension }, From 9797511ff40f45e1125728828051610f0150d432 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 6 Jun 2024 14:24:41 +0200 Subject: [PATCH 5/6] Add option to specify used DRI3 render node Allows users to use a secondary GPU, or to disable DRI3 in case of issues. --- unix/xserver/hw/vnc/Xvnc.man | 5 +++++ unix/xserver/hw/vnc/vncDRI3.c | 13 ++++++++++++- unix/xserver/hw/vnc/vncDRI3.h | 2 ++ unix/xserver/hw/vnc/xvnc.c | 12 ++++++++++++ 4 files changed, 31 insertions(+), 1 deletion(-) diff --git a/unix/xserver/hw/vnc/Xvnc.man b/unix/xserver/hw/vnc/Xvnc.man index 075141faa3..05d34e815c 100644 --- a/unix/xserver/hw/vnc/Xvnc.man +++ b/unix/xserver/hw/vnc/Xvnc.man @@ -46,6 +46,11 @@ Specify pixel format for server to use (BGRnnn or RGBnnn). The default for depth 16 is RGB565 and for depth 24 and 32 is RGB888. . .TP +.B \-rendernode \fIpath\fP +DRM render node to use for DRI3 GPU acceleration. Specify an empty path to +disable DRI3. Default is /dev/dri/renderD128. +. +.TP .B \-interface \fIIP address\fP Listen on interface. By default Xvnc listens on all available interfaces. . diff --git a/unix/xserver/hw/vnc/vncDRI3.c b/unix/xserver/hw/vnc/vncDRI3.c index 3d261667a2..1e643ece56 100644 --- a/unix/xserver/hw/vnc/vncDRI3.c +++ b/unix/xserver/hw/vnc/vncDRI3.c @@ -37,6 +37,8 @@ #error "This code is not compatible with accessors" #endif +const char *renderNode = "/dev/dri/renderD128"; + static DevPrivateKeyRec vncDRI3ScreenPrivateKey; static DevPrivateKeyRec vncDRI3PixmapPrivateKey; @@ -452,6 +454,15 @@ Bool vncDRI3Init(ScreenPtr screen) return FALSE; #endif + /* Empty render node is interpreted as disabling DRI3 */ + if (renderNode[0] == '\0') + return TRUE; + + if (renderNode[0] != '/') { + ErrorF("Invalid render node path \"%s\"\n", renderNode); + return FALSE; + } + if (!dixRegisterPrivateKey(&vncDRI3ScreenPrivateKey, PRIVATE_SCREEN, sizeof(vncDRI3ScreenPrivateRec))) return FALSE; @@ -465,7 +476,7 @@ Bool vncDRI3Init(ScreenPtr screen) #ifdef HAVE_GBM screenPriv = vncDRI3ScreenPrivate(screen); - screenPriv->devicePath = "/dev/dri/renderD128"; + screenPriv->devicePath = renderNode; screenPriv->fd = open(screenPriv->devicePath, O_RDWR|O_CLOEXEC); if (screenPriv->fd < 0) { diff --git a/unix/xserver/hw/vnc/vncDRI3.h b/unix/xserver/hw/vnc/vncDRI3.h index 636171bac7..4f89a25aef 100644 --- a/unix/xserver/hw/vnc/vncDRI3.h +++ b/unix/xserver/hw/vnc/vncDRI3.h @@ -23,6 +23,8 @@ #include +extern const char *renderNode; + Bool vncDRI3Init(ScreenPtr screen); Bool vncDRI3IsHardwarePixmap(PixmapPtr pixmap); diff --git a/unix/xserver/hw/vnc/xvnc.c b/unix/xserver/hw/vnc/xvnc.c index a441f82401..45da17fb6c 100644 --- a/unix/xserver/hw/vnc/xvnc.c +++ b/unix/xserver/hw/vnc/xvnc.c @@ -223,6 +223,9 @@ ddxUseMsg(void) ErrorF("-inetd has been launched from inetd\n"); ErrorF ("-noclipboard disable clipboard settings modification via vncconfig utility\n"); +#ifdef DRI3 + ErrorF("-rendernode PATH DRM render node to use for DRI3\n"); +#endif ErrorF("-verbose [n] verbose startup messages\n"); ErrorF("-quiet minimal startup messages\n"); ErrorF("-version show the server version\n"); @@ -405,6 +408,15 @@ ddxProcessArgument(int argc, char *argv[], int i) return 1; } +#ifdef DRI3 + if (strcmp(argv[i], "-rendernode") == 0) { + CHECK_FOR_REQUIRED_ARGUMENTS(1); + ++i; + renderNode = argv[i]; + return 2; + } +#endif + if (!strcmp(argv[i], "-verbose")) { if (++i < argc && argv[i]) { char *end; From b0d6b1408c0e98c8e2d1dfe1c463c6e575cdf769 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 6 Jun 2024 14:51:52 +0200 Subject: [PATCH 6/6] Automatically pick a suitable DRI3 render node Lay the groundwork for a more intelligent selection of GPU in systems that have multiple cards. This initial implementation simply picks the first GPU that we have permission to open. --- unix/xserver/hw/vnc/Xvnc.man | 3 ++- unix/xserver/hw/vnc/vncDRI3.c | 38 ++++++++++++++++++++++++++++++++--- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/unix/xserver/hw/vnc/Xvnc.man b/unix/xserver/hw/vnc/Xvnc.man index 05d34e815c..fadf9d20a4 100644 --- a/unix/xserver/hw/vnc/Xvnc.man +++ b/unix/xserver/hw/vnc/Xvnc.man @@ -48,7 +48,8 @@ depth 16 is RGB565 and for depth 24 and 32 is RGB888. .TP .B \-rendernode \fIpath\fP DRM render node to use for DRI3 GPU acceleration. Specify an empty path to -disable DRI3. Default is /dev/dri/renderD128. +disable DRI3. Default is \fBauto\fP which makes \fBXvnc\fP pick a suitable +available render node. . .TP .B \-interface \fIIP address\fP diff --git a/unix/xserver/hw/vnc/vncDRI3.c b/unix/xserver/hw/vnc/vncDRI3.c index 1e643ece56..79b56f10dd 100644 --- a/unix/xserver/hw/vnc/vncDRI3.c +++ b/unix/xserver/hw/vnc/vncDRI3.c @@ -22,6 +22,7 @@ #include #include +#include #include #ifdef HAVE_GBM @@ -37,7 +38,7 @@ #error "This code is not compatible with accessors" #endif -const char *renderNode = "/dev/dri/renderD128"; +const char *renderNode = "auto"; static DevPrivateKeyRec vncDRI3ScreenPrivateKey; static DevPrivateKeyRec vncDRI3PixmapPrivateKey; @@ -458,7 +459,8 @@ Bool vncDRI3Init(ScreenPtr screen) if (renderNode[0] == '\0') return TRUE; - if (renderNode[0] != '/') { + if ((renderNode[0] != '/') && + (strcasecmp(renderNode, "auto") != 0)) { ErrorF("Invalid render node path \"%s\"\n", renderNode); return FALSE; } @@ -476,7 +478,37 @@ Bool vncDRI3Init(ScreenPtr screen) #ifdef HAVE_GBM screenPriv = vncDRI3ScreenPrivate(screen); - screenPriv->devicePath = renderNode; + if (strcasecmp(renderNode, "auto") == 0) { + glob_t globbuf; + int ret; + + ret = glob("/dev/dri/renderD*", 0, NULL, &globbuf); + if (ret == GLOB_NOMATCH) { + ErrorF("Could not find any render nodes\n"); + return FALSE; + } + if (ret != 0) { + ErrorF("Failure enumerating render nodes\n"); + return FALSE; + } + + screenPriv->devicePath = NULL; + for (size_t i = 0;i < globbuf.gl_pathc;i++) { + if (access(globbuf.gl_pathv[i], R_OK|W_OK) == 0) { + screenPriv->devicePath = strdup(globbuf.gl_pathv[i]); + break; + } + } + + globfree(&globbuf); + + if (screenPriv->devicePath == NULL) { + ErrorF("Could not find any available render nodes\n"); + return FALSE; + } + } else { + screenPriv->devicePath = renderNode; + } screenPriv->fd = open(screenPriv->devicePath, O_RDWR|O_CLOEXEC); if (screenPriv->fd < 0) {