Changeset 83123 in vbox for trunk/src/VBox/Additions/x11/VBoxClient/display-svga-x11.cpp
- Timestamp:
- Feb 20, 2020 11:38:39 AM (5 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Additions/x11/VBoxClient/display-svga-x11.cpp
r83045 r83123 82 82 int hRandREventBase; 83 83 int hRandRErrorBase; 84 int hEventMask; 84 85 Window rootWindow; 85 86 }; 86 87 static void x11Connect(struct X11CONTEXT *pContext)88 {89 int dummy;90 91 if (pContext->pDisplay != NULL)92 VBClLogFatalError("%s called with bad argument\n", __func__);93 pContext->pDisplay = XOpenDisplay(NULL);94 if (pContext->pDisplay == NULL)95 return;96 // if ( !XQueryExtension(pContext->pDisplay, "RANDR",97 // &pContext->hRandRMajor, &dummy, &dummy)98 if(!XQueryExtension(pContext->pDisplay, "VMWARE_CTRL",99 &pContext->hVMWMajor, &dummy, &dummy))100 {101 XCloseDisplay(pContext->pDisplay);102 pContext->pDisplay = NULL;103 }104 if (!XRRQueryExtension(pContext->pDisplay, &pContext->hRandREventBase, &pContext->hRandRErrorBase))105 {106 XCloseDisplay(pContext->pDisplay);107 pContext->pDisplay = NULL;108 }109 if (!XRRQueryVersion(pContext->pDisplay, &pContext->hRandRMajor, &pContext->hRandRMinor))110 {111 XCloseDisplay(pContext->pDisplay);112 pContext->pDisplay = NULL;113 }114 pContext->rootWindow = DefaultRootWindow(pContext->pDisplay);115 }116 117 #ifndef USE_XRANDR_BIN118 119 static bool checkRecentLinuxKernel(void)120 {121 struct utsname name;122 123 if (uname(&name) == -1)124 VBClLogFatalError("Failed to get kernel name\n");125 if (strcmp(name.sysname, "Linux"))126 return false;127 return (RTStrVersionCompare(name.release, "4.6") >= 0);128 }129 130 131 #define X11_VMW_TOPOLOGY_REQ 2132 133 struct X11REQHEADER134 {135 uint8_t hMajor;136 uint8_t idType;137 uint16_t cd;138 };139 140 struct X11VMWTOPOLOGYREQ141 {142 struct X11REQHEADER header;143 uint32_t idX11Screen;144 uint32_t cScreens;145 uint32_t u32Pad;146 struct X11VMWRECT aRects[1];147 };148 AssertCompileSize(struct X11VMWTOPOLOGYREQ, 24);149 150 #define X11_VMW_TOPOLOGY_REPLY_SIZE 32151 152 #define X11_VMW_RESOLUTION_REQUEST 1153 struct X11VMWRESOLUTIONREQ154 {155 struct X11REQHEADER header;156 uint32_t idX11Screen;157 uint32_t w;158 uint32_t h;159 };160 AssertCompileSize(struct X11VMWRESOLUTIONREQ, 16);161 162 #define X11_VMW_RESOLUTION_REPLY_SIZE 32163 164 #define X11_RANDR_GET_SCREEN_REQUEST 5165 struct X11RANDRGETSCREENREQ166 {167 struct X11REQHEADER header;168 uint32_t hWindow;169 };170 AssertCompileSize(struct X11RANDRGETSCREENREQ, 8);171 172 #define X11_RANDR_GET_SCREEN_REPLY_SIZE 32173 174 /* This was a macro in old Xlib versions and a function in newer ones; the175 * display members touched by the macro were declared as ABI for compatibility176 * reasons. To simplify building with different generations, we duplicate the177 * code. */178 static void x11GetRequest(struct X11CONTEXT *pContext, uint8_t hMajor,179 uint8_t idType, size_t cb, struct X11REQHEADER **ppReq)180 {181 if (pContext->pDisplay->bufptr + cb > pContext->pDisplay->bufmax)182 _XFlush(pContext->pDisplay);183 if (pContext->pDisplay->bufptr + cb > pContext->pDisplay->bufmax)184 VBClLogFatalError("%s display buffer overflow\n", __func__);185 if (cb % 4 != 0)186 VBClLogFatalError("%s bad parameter\n", __func__);187 pContext->pDisplay->last_req = pContext->pDisplay->bufptr;188 *ppReq = (struct X11REQHEADER *)pContext->pDisplay->bufptr;189 (*ppReq)->hMajor = hMajor;190 (*ppReq)->idType = idType;191 (*ppReq)->cd = cb / 4;192 pContext->pDisplay->bufptr += cb;193 pContext->pDisplay->request++;194 }195 196 static void x11SendHints(struct X11CONTEXT *pContext, struct X11VMWRECT *pRects,197 unsigned cRects)198 {199 unsigned i;200 struct X11VMWTOPOLOGYREQ *pReqTopology;201 uint8_t repTopology[X11_VMW_TOPOLOGY_REPLY_SIZE];202 struct X11VMWRESOLUTIONREQ *pReqResolution;203 uint8_t repResolution[X11_VMW_RESOLUTION_REPLY_SIZE];204 205 if (!VALID_PTR(pContext->pDisplay))206 VBClLogFatalError("%s bad display argument\n", __func__);207 if (cRects == 0)208 return;209 /* Try a topology (multiple screen) request. */210 x11GetRequest(pContext, pContext->hVMWMajor, X11_VMW_TOPOLOGY_REQ,211 sizeof(struct X11VMWTOPOLOGYREQ)212 + sizeof(struct X11VMWRECT) * (cRects - 1),213 (struct X11REQHEADER **)&pReqTopology);214 pReqTopology->idX11Screen = DefaultScreen(pContext->pDisplay);215 pReqTopology->cScreens = cRects;216 for (i = 0; i < cRects; ++i)217 pReqTopology->aRects[i] = pRects[i];218 _XSend(pContext->pDisplay, NULL, 0);219 if (_XReply(pContext->pDisplay, (xReply *)&repTopology, 0, xTrue))220 return;221 /* That failed, so try the old single screen set resolution. We prefer222 * simpler code to negligeably improved efficiency, so we just always try223 * both requests instead of doing version checks or caching. */224 x11GetRequest(pContext, pContext->hVMWMajor, X11_VMW_RESOLUTION_REQUEST,225 sizeof(struct X11VMWRESOLUTIONREQ),226 (struct X11REQHEADER **)&pReqResolution);227 pReqResolution->idX11Screen = DefaultScreen(pContext->pDisplay);228 pReqResolution->w = pRects[0].w;229 pReqResolution->h = pRects[0].h;230 if (_XReply(pContext->pDisplay, (xReply *)&repResolution, 0, xTrue))231 return;232 /* What now? */233 VBClLogFatalError("%s failed to set resolution\n", __func__);234 }235 236 /** Call RRGetScreenInfo to wake up the server to the new modes. */237 static void x11GetScreenInfo(struct X11CONTEXT *pContext)238 {239 struct X11RANDRGETSCREENREQ *pReqGetScreen;240 uint8_t repGetScreen[X11_RANDR_GET_SCREEN_REPLY_SIZE];241 242 if (!VALID_PTR(pContext->pDisplay))243 VBClLogFatalError("%s bad display argument\n", __func__);244 x11GetRequest(pContext, pContext->hRandRMajor, X11_RANDR_GET_SCREEN_REQUEST,245 sizeof(struct X11RANDRGETSCREENREQ),246 (struct X11REQHEADER **)&pReqGetScreen);247 pReqGetScreen->hWindow = DefaultRootWindow(pContext->pDisplay);248 _XSend(pContext->pDisplay, NULL, 0);249 if (!_XReply(pContext->pDisplay, (xReply *)&repGetScreen, 0, xTrue))250 VBClLogFatalError("%s failed to set resolution\n", __func__);251 }252 253 #else //#fndef USE_XRANDR_BIN254 87 255 88 #define MAX_MODE_NAME_LEN 64 … … 267 100 RTFILE hDevice; 268 101 }; 269 270 #define DRM_DRIVER_NAME "vmwgfx"271 272 /** DRM version structure. */273 struct DRMVERSION274 {275 int cMajor;276 int cMinor;277 int cPatchLevel;278 size_t cbName;279 char *pszName;280 size_t cbDate;281 char *pszDate;282 size_t cbDescription;283 char *pszDescription;284 };285 AssertCompileSize(struct DRMVERSION, 8 + 7 * sizeof(void *));286 287 #define DRM_IOCTL_VERSION _IOWR('d', 0x00, struct DRMVERSION)288 289 /** Rectangle structure for geometry of a single screen. */290 struct DRMVMWRECT291 {292 int32_t x;293 int32_t y;294 uint32_t w;295 uint32_t h;296 };297 AssertCompileSize(struct DRMVMWRECT, 16);298 299 struct DRMVMWUPDATELAYOUT {300 uint32_t cOutputs;301 uint32_t u32Pad;302 uint64_t ptrRects;303 };304 AssertCompileSize(struct DRMVMWUPDATELAYOUT, 16);305 306 #define DRM_IOCTL_VMW_UPDATE_LAYOUT \307 _IOW('d', 0x40 + 20, struct DRMVMWUPDATELAYOUT)308 102 309 103 struct RANDROUTPUT … … 315 109 bool fEnabled; 316 110 }; 111 112 /** Forward declarations. */ 113 static void x11Connect(struct X11CONTEXT *pContext); 114 115 static bool init(struct X11CONTEXT *pContext) 116 { 117 if (!pContext) 118 return false; 119 x11Connect(pContext); 120 if (pContext->pDisplay == NULL) 121 return false; 122 return true; 123 } 124 125 static void x11Connect(struct X11CONTEXT *pContext) 126 { 127 int dummy; 128 if (pContext->pDisplay != NULL) 129 VBClLogFatalError("%s called with bad argument\n", __func__); 130 pContext->pDisplay = XOpenDisplay(NULL); 131 if (pContext->pDisplay == NULL) 132 return; 133 if(!XQueryExtension(pContext->pDisplay, "VMWARE_CTRL", 134 &pContext->hVMWMajor, &dummy, &dummy)) 135 { 136 XCloseDisplay(pContext->pDisplay); 137 pContext->pDisplay = NULL; 138 } 139 if (!XRRQueryExtension(pContext->pDisplay, &pContext->hRandREventBase, &pContext->hRandRErrorBase)) 140 { 141 XCloseDisplay(pContext->pDisplay); 142 pContext->pDisplay = NULL; 143 } 144 if (!XRRQueryVersion(pContext->pDisplay, &pContext->hRandRMajor, &pContext->hRandRMinor)) 145 { 146 XCloseDisplay(pContext->pDisplay); 147 pContext->pDisplay = NULL; 148 } 149 pContext->hEventMask = RRScreenChangeNotifyMask; 150 if (pContext->hRandRMinor >= 2) 151 pContext->hEventMask |= RRCrtcChangeNotifyMask | 152 RROutputChangeNotifyMask | 153 RROutputPropertyNotifyMask; 154 pContext->rootWindow = DefaultRootWindow(pContext->pDisplay); 155 } 317 156 318 157 /** run the xrandr command without options to get the total # of outputs (monitors) including … … 539 378 } 540 379 541 static void drmConnect(struct DRMCONTEXT *pContext)542 {543 unsigned i;544 RTFILE hDevice;545 546 if (pContext->hDevice != NIL_RTFILE)547 VBClLogFatalError("%s called with bad argument\n", __func__);548 /* Try to open the SVGA DRM device. */549 for (i = 0; i < 128; ++i)550 {551 char szPath[64];552 struct DRMVERSION version;553 char szName[sizeof(DRM_DRIVER_NAME)];554 int rc;555 556 /* Control devices for drm graphics driver control devices go from557 * controlD64 to controlD127. Render node devices go from renderD128558 * to renderD192. The driver takes resize hints via the control device559 * on pre-4.10 kernels and on the render device on newer ones. Try560 * both types. */561 if (i % 2 == 0)562 rc = RTStrPrintf(szPath, sizeof(szPath), "/dev/dri/renderD%u", i / 2 + 128);563 else564 rc = RTStrPrintf(szPath, sizeof(szPath), "/dev/dri/controlD%u", i / 2 + 64);565 if (RT_FAILURE(rc))566 VBClLogFatalError("RTStrPrintf of device path failed, rc=%Rrc\n", rc);567 rc = RTFileOpen(&hDevice, szPath, RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);568 if (RT_FAILURE(rc))569 continue;570 RT_ZERO(version);571 version.cbName = sizeof(szName);572 version.pszName = szName;573 rc = RTFileIoCtl(hDevice, DRM_IOCTL_VERSION, &version, sizeof(version), NULL);574 if ( RT_SUCCESS(rc)575 && !strncmp(szName, DRM_DRIVER_NAME, sizeof(DRM_DRIVER_NAME) - 1)576 && ( version.cMajor > 2577 || (version.cMajor == 2 && version.cMinor >= 9)))578 break;579 hDevice = NIL_RTFILE;580 }581 pContext->hDevice = hDevice;582 }583 584 static void drmSendHints(struct DRMCONTEXT *pContext, struct DRMVMWRECT *paRects,585 unsigned cHeads)586 {587 int rc;588 struct DRMVMWUPDATELAYOUT ioctlLayout;589 590 if (pContext->hDevice == NIL_RTFILE)591 VBClLogFatalError("%s bad device argument\n", __func__);592 ioctlLayout.cOutputs = cHeads;593 ioctlLayout.ptrRects = (uint64_t)paRects;594 rc = RTFileIoCtl(pContext->hDevice, DRM_IOCTL_VMW_UPDATE_LAYOUT,595 &ioctlLayout, sizeof(ioctlLayout), NULL);596 if (RT_FAILURE(rc) && rc != VERR_INVALID_PARAMETER)597 VBClLogFatalError("Failure updating layout, rc=%Rrc\n", rc);598 }599 600 #endif /* #ifndef USE_XRANDR_BIN */601 602 380 static const char *getName() 603 381 { … … 616 394 (void)fDaemonised; 617 395 int rc; 396 uint32_t events; 618 397 /* Do not acknowledge the first event we query for to pick up old events, 619 398 * e.g. from before a guest reboot. */ 620 399 bool fAck = false; 621 400 struct X11CONTEXT x11Context = { NULL }; 622 x11Connect(&x11Context); 623 if (x11Context.pDisplay == NULL) 401 if (!init(&x11Context)) 624 402 return VINF_SUCCESS; 625 626 #ifndef USE_XRANDR_BIN627 unsigned cHeads;628 struct X11VMWRECT aRects[VMW_MAX_HEADS];629 if (checkRecentLinuxKernel())630 return VINF_SUCCESS;631 #else //#ifndef USE_XRANDR_BIN632 403 static struct VMMDevDisplayDef aMonitors[VMW_MAX_HEADS]; 633 struct DRMCONTEXT drmContext = { NIL_RTFILE };634 drmConnect(&drmContext);635 if (drmContext.hDevice == NIL_RTFILE)636 return VINF_SUCCESS;637 unsigned cEnabledMonitors = 0;638 #endif639 404 640 405 rc = VbglR3CtlFilterMask(VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST, 0); … … 656 421 RRProviderPropertyNotifyMask | 657 422 RRResourceChangeNotifyMask; 658 // if (x11Context.hRandRMinor >= 6)659 // eventMask |= RRLeaseNotifyMask;660 661 662 423 for (;;) 663 424 { 664 uint32_t events;665 425 struct VMMDevDisplayDef aDisplays[VMW_MAX_HEADS]; 666 426 uint32_t cDisplaysOut; 667 668 427 /* Query the first size without waiting. This lets us e.g. pick up 669 428 * the last event before a guest reboot when we start again after. */ 670 429 rc = VbglR3GetDisplayChangeRequestMulti(VMW_MAX_HEADS, &cDisplaysOut, aDisplays, fAck); 671 430 fAck = true; 672 673 431 if (RT_FAILURE(rc)) 674 432 VBClLogFatalError("Failed to get display change request, rc=%Rrc\n", rc); 675 433 if (cDisplaysOut > VMW_MAX_HEADS) 676 434 VBClLogFatalError("Display change request contained, rc=%Rrc\n", rc); 677 #ifndef USE_XRANDR_BIN678 for (unsigned i = 0, cHeads = 0; i < cDisplaysOut && i < VMW_MAX_HEADS; ++i)679 {680 if (!(aDisplays[i].fDisplayFlags & VMMDEV_DISPLAY_DISABLED))681 {682 if ((i == 0) || (aDisplays[i].fDisplayFlags & VMMDEV_DISPLAY_ORIGIN))683 {684 aRects[cHeads].x = aDisplays[i].xOrigin < INT16_MAX685 ? (int16_t)aDisplays[i].xOrigin : 0;686 aRects[cHeads].y = aDisplays[i].yOrigin < INT16_MAX687 ? (int16_t)aDisplays[i].yOrigin : 0;688 } else {689 aRects[cHeads].x = aRects[cHeads - 1].x + aRects[cHeads - 1].w;690 aRects[cHeads].y = aRects[cHeads - 1].y;691 }692 aRects[cHeads].w = (int16_t)RT_MIN(aDisplays[i].cx, INT16_MAX);693 aRects[cHeads].h = (int16_t)RT_MIN(aDisplays[i].cy, INT16_MAX);694 ++cHeads;695 }696 }697 x11SendHints(&x11Context, aRects, cHeads);698 x11GetScreenInfo(&x11Context);699 #else700 435 if (cDisplaysOut > 0) 701 436 { … … 720 455 } 721 456 } 722 723 457 /* Create a whole topology and send it to xrandr. */ 724 458 struct RANDROUTPUT aOutputs[VMW_MAX_HEADS]; … … 735 469 } 736 470 setXrandrModes(aOutputs); 737 /* Disable this for now since we want to fix messed up monitor positions in some other way. */ 738 if(0) 739 { 740 /* Additionally update the drm thru ioctl since vmwgfx messes up monitor positions it gets from xserver. */ 741 /* Create an dense (consisting of enabled monitors only) array to pass to DRM. */ 742 cEnabledMonitors = 0; 743 struct DRMVMWRECT aEnabledMonitors[VMW_MAX_HEADS]; 744 for (int j = 0; j < VMW_MAX_HEADS; ++j) 745 { 746 if (!(aMonitors[j].fDisplayFlags & VMMDEV_DISPLAY_DISABLED)) 747 { 748 aEnabledMonitors[cEnabledMonitors].x = aMonitors[j].xOrigin; 749 aEnabledMonitors[cEnabledMonitors].y = aMonitors[j].yOrigin; 750 aEnabledMonitors[cEnabledMonitors].w = aMonitors[j].cx; 751 aEnabledMonitors[cEnabledMonitors].h = aMonitors[j].cy; 752 if (cEnabledMonitors > 0) 753 aEnabledMonitors[cEnabledMonitors].x = aEnabledMonitors[cEnabledMonitors - 1].x + aEnabledMonitors[cEnabledMonitors - 1].w; 754 ++cEnabledMonitors; 755 } 756 } 757 bool fScreenChangeNotifyEvent = false; 758 XRRSelectInput(x11Context.pDisplay, x11Context.rootWindow, eventMask); 759 XSync(x11Context.pDisplay, false); 760 XEvent event; 761 while (XCheckTypedEvent(x11Context.pDisplay, RRScreenChangeNotify + x11Context.hRandREventBase, &event) || 762 XCheckTypedEvent(x11Context.pDisplay, RRNotify + x11Context.hRandREventBase, &event)) 763 fScreenChangeNotifyEvent = true; 764 XRRSelectInput(x11Context.pDisplay, x11Context.rootWindow, 0); 765 766 if (!fScreenChangeNotifyEvent) 767 VBClLogInfo("Did not receive any RRScreenChangeNotify events.\n"); 768 else 769 drmSendHints(&drmContext, aEnabledMonitors, cEnabledMonitors); 770 } 771 } 772 773 #endif 471 } 774 472 do 775 473 {
Note:
See TracChangeset
for help on using the changeset viewer.