aboutsummaryrefslogtreecommitdiffstats
path: root/unix/xserver/hw/vnc
diff options
context:
space:
mode:
Diffstat (limited to 'unix/xserver/hw/vnc')
-rw-r--r--unix/xserver/hw/vnc/Makefile.am10
-rw-r--r--unix/xserver/hw/vnc/Xvnc.man6
-rw-r--r--unix/xserver/hw/vnc/vncDRI3.c537
-rw-r--r--unix/xserver/hw/vnc/vncDRI3.h43
-rw-r--r--unix/xserver/hw/vnc/vncDRI3Draw.c785
-rw-r--r--unix/xserver/hw/vnc/vncHooks.c69
-rw-r--r--unix/xserver/hw/vnc/xvnc.c21
7 files changed, 1442 insertions, 29 deletions
diff --git a/unix/xserver/hw/vnc/Makefile.am b/unix/xserver/hw/vnc/Makefile.am
index f9ed19d9..f9372183 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/Xvnc.man b/unix/xserver/hw/vnc/Xvnc.man
index e43ba150..b9c429f7 100644
--- a/unix/xserver/hw/vnc/Xvnc.man
+++ b/unix/xserver/hw/vnc/Xvnc.man
@@ -46,6 +46,12 @@ 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 \fBauto\fP which makes \fBXvnc\fP pick a suitable
+available render node.
+.
+.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
new file mode 100644
index 00000000..79b56f10
--- /dev/null
+++ b/unix/xserver/hw/vnc/vncDRI3.c
@@ -0,0 +1,537 @@
+/* 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 <dix-config.h>
+#endif
+
+#include <errno.h>
+#include <fcntl.h>
+#include <glob.h>
+#include <unistd.h>
+
+#ifdef HAVE_GBM
+#include <gbm.h>
+#endif
+
+#include "vncDRI3.h"
+#include <dri3.h>
+#include <fb.h>
+#include <misyncshm.h>
+
+#ifdef FB_ACCESS_WRAPPER
+#error "This code is not compatible with accessors"
+#endif
+
+const char *renderNode = "auto";
+
+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
+
+ /* Empty render node is interpreted as disabling DRI3 */
+ if (renderNode[0] == '\0')
+ return TRUE;
+
+ if ((renderNode[0] != '/') &&
+ (strcasecmp(renderNode, "auto") != 0)) {
+ ErrorF("Invalid render node path \"%s\"\n", renderNode);
+ return FALSE;
+ }
+
+ 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);
+
+ 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) {
+ 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 00000000..4f89a25a
--- /dev/null
+++ b/unix/xserver/hw/vnc/vncDRI3.h
@@ -0,0 +1,43 @@
+/* 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 <dix.h>
+
+extern const char *renderNode;
+
+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 00000000..8aa6625d
--- /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 <dix-config.h>
+#endif
+
+#include "vncDRI3.h"
+
+#include <fb.h>
+#include <gcstruct.h>
+#include <pixmapstr.h>
+
+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/vncHooks.c b/unix/xserver/hw/vnc/vncHooks.c
index 3838c10d..7fe35ada 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(&reg, &box, 1);
- RegionIntersect(&reg, &reg, &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(&reg, &box, 1);
+ RegionIntersect(&reg, &reg, &pWin->clipList);
+ } else {
+ RegionNull(&reg);
+ }
(*pScreen->ClearToBackground) (pWin, x, y, w, h, generateExposures);
diff --git a/unix/xserver/hw/vnc/xvnc.c b/unix/xserver/hw/vnc/xvnc.c
index 4ee1cd1b..45da17fb 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"
@@ -222,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");
@@ -404,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;
@@ -1088,6 +1101,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 */
@@ -1110,7 +1129,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 },