The goal: Use the VESA driver and start at a resolution of 1024x768 with a higher resolution being available using 'xrandr -s 1280x1024'.
This matches what the VMware driver is able to do. Why we want this: Our data center uses a "switch" that allows one physical monitor to be used with many rack mounted computers. The KVM switch (Keyboard Video Mouse switch) uses dongles to send the video signal over Cat5 cabling. The dongles are connected in series and relay switches in each dongle are used to address a particular machine. Video bandwidth varies depending on the length of the cable (as controlled by the relays) and the solution does not support DDC/EDID. The VESA driver is preferred by us as it works with all machines and having the best video performance is not too important to us. The smaller resolution of 1024x768 is the best startup default as it works for machines that have the lowest video bandwidth. This resolution must be manually configured in xorg.conf because a system with no xorg.conf will use the highest resolution it finds in the VESA BIOS (which for some hardware is much too large). We want to be able to 'xrandr -s 1280x1024' (and back to 1024x768) just to see if the higher resolution is OK (some machines have sufficient video bandwidth for this mode). This quick test would be better that having to quit X and edit xorg.conf by hand. Some machines boot from the network (PXE) and have no permanent storage, so we can not edit xorg.conf one time and leave it that way. The hoped for solution: From our xorg.conf: Modes "1024x768" "1280x1024" We had hoped that just adding a second mode would do the trick. Alas, the virtual display is calculated to accommodate the larger resolution and the machine starts in 1024x768 but it's a viewport into a virtual display of 1280x1024. This is the documented behavior, but it'd not what we want. Adding this: Virtual 1024 768 Fixes the "viewport" problem, but the larger mode becomes unavailable (xrandr does not list it). Also, xrandr can not be used to add it later as it errors with: "screen cannot be larger than 1024x768" The attempted hack: We noticed that another driver behaved differently. The VMware driver (in a virtual machine, forget about our KVM switch for now) will start at 1024x768 when configured in xorg.conf, but xrandr will list lots of larger modes (that we did not specify) and xrandr can be used to switch to them. Upon inspection of the VMware driver's source code, near the end of VMWAREScreenInit() (what ScreenInit() points to), we see in vmware.c: /* * We explicitly add a set of default modes because the X server will * not include modes larger than the initial one. */ { unsigned int i; unsigned int numModes = sizeof (VMWAREDefaultModes) / sizeof *(VMWAREDefaultModes); char name[10]; for (i = 0; i < numModes; i++) { const VMWAREDefaultMode *mode = &VMWAREDefaultModes[i]; /* Only modes that fit the hardware maximums should be added. */ if (mode->width <= pVMWARE->maxWidth && mode->height <= pVMWARE->maxHeight) { snprintf(name, 10, "%dx%d", mode->width, mode->height); VMWAREAddDisplayMode(pScrn, name, mode->width, mode->height); } } } Since the VMware driver exhibits our desired behaviour (start at a lower rez and allow xrandr switching to a higher rez without virtual display viewport wierdness), we tried to hack that same idea into the VESA driver. Our hack (please see attached), successfully allows xrandr switching to the higher rez and the monitor's info panel confirms that the rez and timing are correct. The problem seems to be that the virtual display size is not being updated to match the higher resolution and appears to be stuck at the lower rez. This results in an unhappy X display that looks like there is corrupt video memory in the areas outside the original resolution. Assistance required: We are not skilled X hackers and it's nice that we've even been able to get this far without really knowing what we're doing... :^) We are hoping that there is a way to get the virtual display size to update with the video mode change (a la the VMware driver). It would be great if someone could please explain how this might be done. It's not clear to us why this is working for the VMware driver... Also, if we can get this working in the VESA driver, would this be acceptable (if given some polish vs. using one hard-coded mode) as a patch? If the current behaviour is deemed to be desirable, maybe we could create a new VESA driver specific option that would cause the driver to add higher modes if specified? We like that X can run without a conf file these days, but if a conf file is being used, it would be nice to have the flexibility to start at a lower rez and still support switching to a higher rez (like our MS Windows machines). Thanks for your consideration!
--- vesa.c.org 2015-06-20 12:00:39.000000000 -0700 +++ vesa.c 2015-07-02 09:48:04.776149826 -0700 @@ -65,6 +65,9 @@ #include <X11/extensions/dpms.h> #endif +// (qqqq) - Taken from xserver-xorg-video-vmware (vmware.h & vmware.c) +#include "xf86.h" +static DisplayModeRec *VMWAREAddDisplayMode(ScrnInfoPtr pScrn, const char *name, int width, int height); /* Mandatory functions */ static const OptionInfoRec * VESAAvailableOptions(int chipid, int busid); @@ -1109,6 +1112,17 @@ xf86DPMSInit(pScreen, VESADisplayPowerManagementSet, 0); + /* (qqqq) + * Idea and code copied from the vmware driver. Explictly add 1280x1024 + * because the X server will not include modes larger than the initial one + * of 1024x768. + */ + { + char name[10]; + snprintf(name, 10, "%dx%d", 1280, 1024); + VMWAREAddDisplayMode(pScrn, name, 1280, 1024); + } + /* Report any unused options (only for the first generation) */ if (serverGeneration == 1) xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options); @@ -1681,6 +1695,67 @@ VBEDPMSSet(pVesa->pVbe, mode); } +/* (qqqq) + * Taken from vmware driver and agrees w/: + * ./xorg-server-1.10.4/hw/xfree86/common/vesamodes + */ +#define MODEPREFIX NULL, NULL, NULL, 0, M_T_BUILTIN +#define MODESUFFIX 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,FALSE,FALSE,0,NULL,0,0.0,0.0 +static DisplayModeRec VMwareModes[] = { // really VESA modes + { MODEPREFIX, 108000, 1280, 1328, 1440, 1688, 0, 1024, 1025, 1028, 1066, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, // 1280x1024@60Hz +}; + +static DisplayModeRec * +VMWAREAddDisplayMode(ScrnInfoPtr pScrn, const char *name, int width, int height) +{ + int id; // the VESA BIOS mode number + DisplayModeRec *new_display_mode; // what we are building/adding + DisplayModePtr timing_params = NULL; // we get timing info from here + VbeModeInfoBlock *modeinfoblock; // we get VESA BIOS info from here + VbeModeInfoData *data; // holds id and VbeModeInfoBlock + VESAPtr pVesa = VESAGetRec(pScrn); // pointer to the VESA BIOS + + new_display_mode = malloc(sizeof(DisplayModeRec)); + memset(new_display_mode, 0, sizeof *new_display_mode); + + new_display_mode->name = malloc(strlen(name) + 1); + strcpy(new_display_mode->name, name); + new_display_mode->status = MODE_OK; + new_display_mode->type = M_T_BUILTIN; + new_display_mode->HDisplay = width; + new_display_mode->VDisplay = height; + + // if (pScrn->bitsPerPixel == 8 15 16 24 + id = 282; // VESA mode ID 0x11A (1280×1024x16bpp) + + data = xnfcalloc(sizeof(VbeModeInfoData), 1); + data->mode = id; + if ((modeinfoblock = VBEGetModeInfo(pVesa->pVbe, data->mode)) == NULL) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "VMWAREAddDisplayMode: no modeinfoblock\n"); + return NULL; + } else { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "VMWAREAddDisplayMode: got modeinfoblock\n"); + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "VMWAREAddDisplayMode: XResolution: %d\n", modeinfoblock->XResolution); + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "VMWAREAddDisplayMode: YResolution: %d\n", modeinfoblock->YResolution); + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "VMWAREAddDisplayMode: BitsPerPixel: %d\n", modeinfoblock->BitsPerPixel); + } + data->data = modeinfoblock; + + // VESASetMode() needs this... + new_display_mode->PrivSize = sizeof(VbeModeInfoData); + new_display_mode->Private = (INT32*)data; + + timing_params = xf86DuplicateMode(&(VMwareModes[0])); + VESASetModeParameters(pVesa->pVbe, new_display_mode, timing_params); + + new_display_mode->next = pScrn->modes; + new_display_mode->prev = pScrn->modes->prev; + pScrn->modes->prev->next = new_display_mode; + pScrn->modes->prev = new_display_mode; + + return new_display_mode; +} + /*********************************************************************** * DGA stuff ***********************************************************************/
_______________________________________________ xorg-devel@lists.x.org: X.Org development Archives: http://lists.x.org/archives/xorg-devel Info: http://lists.x.org/mailman/listinfo/xorg-devel