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