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@zetier.com> Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1749>
This commit is contained in:
parent
b61647f3a1
commit
7933cc24d0
|
@ -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,16 +887,19 @@ static Bool
|
|||
vfbRandRInit(ScreenPtr pScreen)
|
||||
{
|
||||
rrScrPrivPtr pScrPriv;
|
||||
|
||||
#if RANDR_12_INTERFACE
|
||||
RRModePtr mode;
|
||||
RRCrtcPtr crtc;
|
||||
RROutputPtr output;
|
||||
xRRModeInfo modeInfo;
|
||||
char name[64];
|
||||
int i;
|
||||
vfbScreenInfoPtr pvfb = &vfbScreens[pScreen->myNum];
|
||||
#endif
|
||||
int mmWidth, mmHeight;
|
||||
|
||||
if (!RRScreenInit (pScreen))
|
||||
if (!RRScreenInit(pScreen))
|
||||
return FALSE;
|
||||
pScrPriv = rrGetScrPriv(pScreen);
|
||||
pScrPriv->rrGetInfo = vfbRRGetInfo;
|
||||
|
@ -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);
|
||||
|
||||
RRScreenSetSizeRange (pScreen,
|
||||
1, 1,
|
||||
pScreen->width, pScreen->height);
|
||||
for (i = 0; i < pvfb->numCrtcs; i++) {
|
||||
vfbCrtcInfoPtr pvci = &pvfb->crtcs[i];
|
||||
|
||||
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);
|
||||
mmWidth = pvci->width * 25.4 / monitorResolution;
|
||||
mmHeight = pvci->height * 25.4 / monitorResolution;
|
||||
|
||||
mode = RRModeGet (&modeInfo, name);
|
||||
if (!mode)
|
||||
return FALSE;
|
||||
|
||||
crtc = RRCrtcCreate (pScreen, NULL);
|
||||
crtc = RRCrtcCreate(pScreen, pvci);
|
||||
if (!crtc)
|
||||
return FALSE;
|
||||
|
||||
/* This is to avoid xrandr to complain about the gamma missing */
|
||||
RRCrtcGammaSetSize (crtc, 256);
|
||||
/* Set gamma to avoid xrandr complaints */
|
||||
RRCrtcGammaSetSize(crtc, 256);
|
||||
|
||||
output = RROutputCreate (pScreen, "screen", 6, NULL);
|
||||
/* 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))
|
||||
if (!RROutputSetClones(output, NULL, 0))
|
||||
return FALSE;
|
||||
if (!RROutputSetModes (output, &mode, 1, 0))
|
||||
if (!RROutputSetCrtcs(output, &crtc, 1))
|
||||
return FALSE;
|
||||
if (!RROutputSetCrtcs (output, &crtc, 1))
|
||||
if (!RROutputSetConnection(output, RR_Connected))
|
||||
return FALSE;
|
||||
if (!RROutputSetConnection (output, RR_Connected))
|
||||
if (!RROutputSetPhysicalSize(output, mmWidth, mmHeight))
|
||||
return FALSE;
|
||||
if (!RROutputSetPhysicalSize (output, mmWidth, mmHeight))
|
||||
|
||||
/* 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;
|
||||
RRCrtcNotify (crtc, mode, 0, 0, RR_Rotate_0, NULL, 1, &output);
|
||||
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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue