From 0527c9f76effeb6acd5345fc770a4ebc2a0fce9b Mon Sep 17 00:00:00 2001 From: Lauri Kasanen Date: Tue, 25 Jul 2023 13:56:05 +0000 Subject: [PATCH] Add support for compositing --- unix/xserver/hw/vnc/dri3.c | 121 ++++++++++++++++++++++++++++++++++++- unix/xserver120.patch | 20 ++++++ 2 files changed, 138 insertions(+), 3 deletions(-) diff --git a/unix/xserver/hw/vnc/dri3.c b/unix/xserver/hw/vnc/dri3.c index d0540de..8a78d3b 100644 --- a/unix/xserver/hw/vnc/dri3.c +++ b/unix/xserver/hw/vnc/dri3.c @@ -55,6 +55,15 @@ typedef struct gbm_pixmap gbm_pixmap; static DevPrivateKeyRec dri3_pixmap_private_key; static struct timeval start; +#define MAX_TEXPIXMAPS 32 +static PixmapPtr texpixmaps[MAX_TEXPIXMAPS]; +static uint32_t num_texpixmaps; +static CARD32 update_texpixmaps(OsTimerPtr timer, CARD32 time, void *arg); +static OsTimerPtr texpixmaptimer; + +void xvnc_sync_dri3_textures(void); +void xvnc_sync_dri3_pixmap(PixmapPtr pixmap); +void xvnc_init_dri3(void); static int @@ -99,6 +108,29 @@ static gbm_pixmap *gbm_pixmap_get(PixmapPtr pixmap) return dixLookupPrivate(&pixmap->devPrivates, &dri3_pixmap_private_key); } +static void add_texpixmap(PixmapPtr pix) +{ + uint32_t i; + for (i = 0; i < MAX_TEXPIXMAPS; i++) { + if (texpixmaps[i] == pix) + return; + } + + for (i = 0; i < MAX_TEXPIXMAPS; i++) { + if (!texpixmaps[i]) { + texpixmaps[i] = pix; + pix->refcnt++; + num_texpixmaps++; + // start if not running + if (!texpixmaptimer) + texpixmaptimer = TimerSet(NULL, 0, 16, update_texpixmaps, NULL); + return; + } + } + + ErrorF("Max number of texpixmaps reached\n"); +} + static PixmapPtr create_pixmap_for_bo(ScreenPtr screen, struct gbm_bo *bo, CARD8 depth) { @@ -164,14 +196,33 @@ xvnc_fds_from_pixmap(ScreenPtr screen, PixmapPtr pixmap, int *fds, uint64_t *modifier) { gbm_pixmap *gp = gbm_pixmap_get(pixmap); - if (!gp) - return 0; + + if (!gp) { + gp = calloc(1, sizeof(gbm_pixmap)); + if (!gp) + return 0; + gp->bo = gbm_bo_create(priv.gbm, + pixmap->drawable.width, + pixmap->drawable.height, + gbm_format_for_depth(pixmap->drawable.depth), + (pixmap->usage_hint == CREATE_PIXMAP_USAGE_SHARED ? + GBM_BO_USE_LINEAR : 0) | + GBM_BO_USE_RENDERING | GBM_BO_USE_SCANOUT); + if (!gp->bo) { + ErrorF("Failed to create bo\n"); + return 0; + } + + dri3_pixmap_set_private(pixmap, gp); + } fds[0] = gbm_bo_get_fd(gp->bo); strides[0] = gbm_bo_get_stride(gp->bo); offsets[0] = 0; *modifier = DRM_FORMAT_MOD_INVALID; + add_texpixmap(pixmap); + return 1; } @@ -219,12 +270,13 @@ void xvnc_sync_dri3_pixmap(PixmapPtr pixmap) void *ptr; uint32_t stride, w, h; void *opaque = NULL; + gbm_pixmap *gp; // We may not be running on hw if there's a compositor using PRESENT on llvmpipe if (!driNode) return; - gbm_pixmap *gp = gbm_pixmap_get(pixmap); + gp = gbm_pixmap_get(pixmap); if (!gp) { //ErrorF("Present tried to copy from a non-dri3 pixmap\n"); return; @@ -252,6 +304,69 @@ void xvnc_sync_dri3_pixmap(PixmapPtr pixmap) gbm_bo_unmap(gp->bo, opaque); } +void xvnc_sync_dri3_textures(void) +{ + // Sync the tracked pixmaps into their textures (bos) + // This is a bit of an ugly solution, but we don't know + // when the pixmaps have changed nor when the textures are read. + // + // This is called both from the global damage report and the timer, + // to account for cases that do not use the damage report. + + uint32_t i, y; + gbm_pixmap *gp; + uint8_t *src, *dst; + uint32_t srcstride, dststride; + void *opaque = NULL; + + for (i = 0; i < MAX_TEXPIXMAPS; i++) { + if (!texpixmaps[i]) + continue; + if (texpixmaps[i]->refcnt == 1) { + // We are the only user left, delete it + texpixmaps[i]->drawable.pScreen->DestroyPixmap(texpixmaps[i]); + texpixmaps[i] = NULL; + num_texpixmaps--; + continue; + } + + gp = gbm_pixmap_get(texpixmaps[i]); + opaque = NULL; + dst = gbm_bo_map(gp->bo, 0, 0, + texpixmaps[i]->drawable.width, + texpixmaps[i]->drawable.height, + GBM_BO_TRANSFER_WRITE, &dststride, &opaque); + if (!dst) { + ErrorF("gbm map failed, errno %d\n", errno); + continue; + } + + srcstride = texpixmaps[i]->devKind; + src = texpixmaps[i]->devPrivate.ptr; + + for (y = 0; y < texpixmaps[i]->drawable.height; y++) { + memcpy(dst, src, srcstride); + dst += dststride; + src += srcstride; + } + + gbm_bo_unmap(gp->bo, opaque); + } +} + +static CARD32 update_texpixmaps(OsTimerPtr timer, CARD32 time, void *arg) +{ + xvnc_sync_dri3_textures(); + + if (!num_texpixmaps) { + TimerFree(texpixmaptimer); + texpixmaptimer = NULL; + return 0; + } + + return 16; // Reschedule next tick +} + void xvnc_init_dri3(void) { memset(&priv, 0, sizeof(priv)); diff --git a/unix/xserver120.patch b/unix/xserver120.patch index bd9f3ea..5bb4668 100644 --- a/unix/xserver120.patch +++ b/unix/xserver120.patch @@ -111,3 +111,23 @@ Index: xserver/mi/miinitext.c gc = GetScratchGC(drawable->depth, screen); if (update) { ChangeGCVal changes[2]; +--- xserver.orig/damageext/damageext.c 2019-02-26 21:28:50.000000000 +0200 ++++ xserver/damageext/damageext.c 2023-03-21 12:52:58.411647186 +0200 +@@ -87,6 +87,8 @@ + *h = draw->height; + } + ++void xvnc_sync_dri3_textures(void); ++ + static void + DamageExtNotify(DamageExtPtr pDamageExt, BoxPtr pBoxes, int nBoxes) + { +@@ -97,6 +99,8 @@ + + damageGetGeometry(pDrawable, &x, &y, &w, &h); + ++ xvnc_sync_dri3_textures(); ++ + UpdateCurrentTimeIf(); + ev = (xDamageNotifyEvent) { + .type = DamageEventBase + XDamageNotify,