xserver: Branch 'master'

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Thu Feb 13 23:27:24 UTC 2025


 hw/vfb/InitOutput.c |  191 ++++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 143 insertions(+), 48 deletions(-)

New commits:
commit 7933cc24d0f4eae9009eaeaaaa1a791ebc9b3947
Author: Andy Myers <andy.myers at zetier.com>
Date:   Fri Dec 6 15:16:50 2024 -0500

    xvfb: Add multiple CRTC support
    
    Multiple CRTCs can be added on a per-screen basis with the new -crtcs
    option. Each CRTC has one associated output. Outputs beyond the first
    are disabled by default and can be enabled by setting a mode. Outputs
    can be disabled again by setting the associated CRTC's mode and output
    to None.
    
    Signed-off-by: Andy Myers <andy.myers at zetier.com>
    Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1749>

diff --git a/hw/vfb/InitOutput.c b/hw/vfb/InitOutput.c
index 773831afd..94a227b40 100644
--- a/hw/vfb/InitOutput.c
+++ b/hw/vfb/InitOutput.c
@@ -81,8 +81,17 @@ from The Open Group.
 #define VFB_DEFAULT_WHITEPIXEL    1
 #define VFB_DEFAULT_BLACKPIXEL    0
 #define VFB_DEFAULT_LINEBIAS      0
+#define VFB_DEFAULT_NUM_CRTCS     1
 #define XWD_WINDOW_NAME_LEN      60
 
+typedef struct {
+    int width;
+    int height;
+    int x;
+    int y;
+    int numOutputs;
+} vfbCrtcInfo, *vfbCrtcInfoPtr;
+
 typedef struct {
     int width;
     int paddedBytesWidth;
@@ -92,6 +101,8 @@ typedef struct {
     int bitsPerPixel;
     int sizeInBytes;
     int ncolors;
+    int numCrtcs;
+    vfbCrtcInfoPtr crtcs;
     char *pfbMemory;
     XWDColor *pXWDCmap;
     XWDFileHeader *pXWDHeader;
@@ -140,6 +151,43 @@ static Bool Render = TRUE;
     if (needswap) { CARD32 _s = _src; cpswapl(_s, _dst); } \
     else _dst = _src;
 
+static void
+vfbAddCrtcInfo(vfbScreenInfoPtr screen, int numCrtcs)
+{
+    int i;
+    int count = numCrtcs - screen->numCrtcs;
+
+    if (count > 0) {
+        vfbCrtcInfoPtr crtcs =
+            reallocarray(screen->crtcs, numCrtcs, sizeof(*crtcs));
+        if (!crtcs)
+            FatalError("Not enough memory for %d CRTCs", numCrtcs);
+
+        memset(crtcs + screen->numCrtcs, 0, count * sizeof(*crtcs));
+
+        for (i = screen->numCrtcs; i < numCrtcs; ++i) {
+            crtcs[i].width = screen->width;
+            crtcs[i].height = screen->height;
+        }
+
+        screen->crtcs = crtcs;
+        screen->numCrtcs = numCrtcs;
+    }
+}
+
+static vfbScreenInfoPtr
+vfbInitializeScreenInfo(vfbScreenInfoPtr screen)
+{
+    *screen = defaultScreenInfo;
+    vfbAddCrtcInfo(screen, VFB_DEFAULT_NUM_CRTCS);
+
+    /* First CRTC initializes with one output */
+    if (screen->numCrtcs > 0)
+        screen->crtcs[0].numOutputs = 1;
+
+    return screen;
+}
+
 static void
 vfbInitializePixmapDepths(void)
 {
@@ -196,6 +244,8 @@ freeScreenInfo(vfbScreenInfoPtr pvfb)
         free(pvfb->pXWDHeader);
         break;
     }
+
+    free(pvfb->crtcs);
 }
 
 void
@@ -262,6 +312,9 @@ ddxUseMsg(void)
 #ifdef MITSHM
     ErrorF("-shmem                 put framebuffers in shared memory\n");
 #endif
+
+    ErrorF("-crtcs n               number of CRTCs per screen (default: %d)\n",
+           VFB_DEFAULT_NUM_CRTCS);
 }
 
 int
@@ -277,7 +330,7 @@ ddxProcessArgument(int argc, char *argv[], int i)
     }
 
     if (lastScreen == -1)
-        currentScreen = &defaultScreenInfo;
+        currentScreen = vfbInitializeScreenInfo(&defaultScreenInfo);
     else
         currentScreen = &vfbScreens[lastScreen];
 
@@ -301,7 +354,7 @@ ddxProcessArgument(int argc, char *argv[], int i)
             if (!vfbScreens)
                 FatalError("Not enough memory for screen %d\n", screenNum);
             for (; vfbNumScreens <= screenNum; ++vfbNumScreens)
-                vfbScreens[vfbNumScreens] = defaultScreenInfo;
+                vfbInitializeScreenInfo(&vfbScreens[vfbNumScreens]);
         }
 
         if (3 != sscanf(argv[i + 2], "%dx%dx%d",
@@ -382,6 +435,24 @@ ddxProcessArgument(int argc, char *argv[], int i)
     }
 #endif
 
+    if (strcmp(argv[i], "-crtcs") == 0) {       /* -crtcs n */
+        int numCrtcs;
+
+        CHECK_FOR_REQUIRED_ARGUMENTS(1);
+        numCrtcs = atoi(argv[i + 1]);
+
+        if (numCrtcs < 1) {
+            ErrorF("Invalid number of CRTCs %d\n", numCrtcs);
+            UseMsg();
+            FatalError("Invalid number of CRTCs (%d) passed to -crtcs\n",
+                       numCrtcs);
+
+        }
+
+        vfbAddCrtcInfo(currentScreen, numCrtcs);
+        return 2;
+    }
+
     return 0;
 }
 
@@ -785,10 +856,22 @@ vfbRRCrtcSet(ScreenPtr pScreen,
              int       x,
              int       y,
              Rotation  rotation,
-             int       numOutput,
+             int       numOutputs,
              RROutputPtr *outputs)
 {
-  return RRCrtcNotify(crtc, mode, x, y, rotation, NULL, numOutput, outputs);
+    vfbCrtcInfoPtr pvci = crtc->devPrivate;
+
+    if (pvci) {
+        if (mode) {
+            pvci->width = mode->mode.width;
+            pvci->height = mode->mode.height;
+        }
+
+        pvci->x = x;
+        pvci->y = y;
+        pvci->numOutputs = numOutputs;
+    }
+    return RRCrtcNotify(crtc, mode, x, y, rotation, NULL, numOutputs, outputs);
 }
 
 static Bool
@@ -804,17 +887,20 @@ static Bool
 vfbRandRInit(ScreenPtr pScreen)
 {
     rrScrPrivPtr pScrPriv;
+
 #if RANDR_12_INTERFACE
-    RRModePtr  mode;
-    RRCrtcPtr  crtc;
-    RROutputPtr        output;
+    RRModePtr mode;
+    RRCrtcPtr crtc;
+    RROutputPtr output;
     xRRModeInfo modeInfo;
-    char       name[64];
+    char name[64];
+    int i;
+    vfbScreenInfoPtr pvfb = &vfbScreens[pScreen->myNum];
 #endif
     int mmWidth, mmHeight;
 
-    if (!RRScreenInit (pScreen))
-       return FALSE;
+    if (!RRScreenInit(pScreen))
+        return FALSE;
     pScrPriv = rrGetScrPriv(pScreen);
     pScrPriv->rrGetInfo = vfbRRGetInfo;
 #if RANDR_12_INTERFACE
@@ -827,44 +913,53 @@ vfbRandRInit(ScreenPtr pScreen)
     pScrPriv->rrOutputValidateMode = vfbRROutputValidateMode;
     pScrPriv->rrModeDestroy = NULL;
 
-    mmWidth = pScreen->width * 25.4 / monitorResolution;
-    mmHeight = pScreen->height * 25.4 / monitorResolution;
-
-    RRScreenSetSizeRange (pScreen,
-                         1, 1,
-                         pScreen->width, pScreen->height);
-
-    sprintf (name, "%dx%d", pScreen->width, pScreen->height);
-    memset (&modeInfo, '\0', sizeof (modeInfo));
-    modeInfo.width = pScreen->width;
-    modeInfo.height = pScreen->height;
-    modeInfo.nameLength = strlen (name);
-
-    mode = RRModeGet (&modeInfo, name);
-    if (!mode)
-       return FALSE;
-
-    crtc = RRCrtcCreate (pScreen, NULL);
-    if (!crtc)
-       return FALSE;
-
-    /* This is to avoid xrandr to complain about the gamma missing */
-    RRCrtcGammaSetSize (crtc, 256);
-
-    output = RROutputCreate (pScreen, "screen", 6, NULL);
-    if (!output)
-       return FALSE;
-    if (!RROutputSetClones (output, NULL, 0))
-       return FALSE;
-    if (!RROutputSetModes (output, &mode, 1, 0))
-       return FALSE;
-    if (!RROutputSetCrtcs (output, &crtc, 1))
-       return FALSE;
-    if (!RROutputSetConnection (output, RR_Connected))
-       return FALSE;
-    if (!RROutputSetPhysicalSize (output, mmWidth, mmHeight))
-       return FALSE;
-    RRCrtcNotify (crtc, mode, 0, 0, RR_Rotate_0, NULL, 1, &output);
+    RRScreenSetSizeRange(pScreen, 1, 1, pScreen->width, pScreen->height);
+
+    for (i = 0; i < pvfb->numCrtcs; i++) {
+        vfbCrtcInfoPtr pvci = &pvfb->crtcs[i];
+
+        mmWidth = pvci->width * 25.4 / monitorResolution;
+        mmHeight = pvci->height * 25.4 / monitorResolution;
+
+        crtc = RRCrtcCreate(pScreen, pvci);
+        if (!crtc)
+            return FALSE;
+
+        /* Set gamma to avoid xrandr complaints */
+        RRCrtcGammaSetSize(crtc, 256);
+
+        /* Setup an Output for each CRTC: 'screen' for the first, then 'screen_N' */
+        snprintf(name, sizeof(name), i == 0 ? "screen" : "screen_%d", i);
+        output = RROutputCreate(pScreen, name, strlen(name), NULL);
+        if (!output)
+            return FALSE;
+        if (!RROutputSetClones(output, NULL, 0))
+            return FALSE;
+        if (!RROutputSetCrtcs(output, &crtc, 1))
+            return FALSE;
+        if (!RROutputSetConnection(output, RR_Connected))
+            return FALSE;
+        if (!RROutputSetPhysicalSize(output, mmWidth, mmHeight))
+            return FALSE;
+
+        /* Setup a Mode and notify only for CRTCs with Outputs */
+        if (pvci->numOutputs > 0) {
+            snprintf(name, sizeof(name), "%dx%d", pvci->width, pvci->height);
+            memset(&modeInfo, '\0', sizeof(modeInfo));
+            modeInfo.width = pvci->width;
+            modeInfo.height = pvci->height;
+            modeInfo.nameLength = strlen(name);
+
+            mode = RRModeGet(&modeInfo, name);
+            if (!mode)
+                return FALSE;
+            if (!RROutputSetModes(output, &mode, 1, 0))
+                return FALSE;
+            if (!RRCrtcNotify(crtc, mode, pvci->x, pvci->y, RR_Rotate_0, NULL,
+                              1, &output))
+                return FALSE;
+        }
+    }
 #endif
     return TRUE;
 }


More information about the xorg-commit mailing list