VirtualBox

Changeset 83123 in vbox for trunk/src/VBox/Additions/x11


Ignore:
Timestamp:
Feb 20, 2020 11:38:39 AM (5 years ago)
Author:
vboxsync
Message:

bugref:9637. Some cleanup.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Additions/x11/VBoxClient/display-svga-x11.cpp

    r83045 r83123  
    8282    int hRandREventBase;
    8383    int hRandRErrorBase;
     84    int hEventMask;
    8485    Window rootWindow;
    8586};
    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_BIN
    118 
    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 2
    132 
    133 struct X11REQHEADER
    134 {
    135     uint8_t hMajor;
    136     uint8_t idType;
    137     uint16_t cd;
    138 };
    139 
    140 struct X11VMWTOPOLOGYREQ
    141 {
    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 32
    151 
    152 #define X11_VMW_RESOLUTION_REQUEST 1
    153 struct X11VMWRESOLUTIONREQ
    154 {
    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 32
    163 
    164 #define X11_RANDR_GET_SCREEN_REQUEST 5
    165 struct X11RANDRGETSCREENREQ
    166 {
    167     struct X11REQHEADER header;
    168     uint32_t hWindow;
    169 };
    170 AssertCompileSize(struct X11RANDRGETSCREENREQ, 8);
    171 
    172 #define X11_RANDR_GET_SCREEN_REPLY_SIZE 32
    173 
    174 /* This was a macro in old Xlib versions and a function in newer ones; the
    175  * display members touched by the macro were declared as ABI for compatibility
    176  * reasons.  To simplify building with different generations, we duplicate the
    177  * 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 prefer
    222      * simpler code to negligeably improved efficiency, so we just always try
    223      * 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_BIN
    25487
    25588#define MAX_MODE_NAME_LEN 64
     
    267100    RTFILE hDevice;
    268101};
    269 
    270 #define DRM_DRIVER_NAME "vmwgfx"
    271 
    272 /** DRM version structure. */
    273 struct DRMVERSION
    274 {
    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 DRMVMWRECT
    291 {
    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)
    308102
    309103struct RANDROUTPUT
     
    315109    bool fEnabled;
    316110};
     111
     112/** Forward declarations. */
     113static void x11Connect(struct X11CONTEXT *pContext);
     114
     115static 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
     125static 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}
    317156
    318157/** run the xrandr command without options to get the total # of outputs (monitors) including
     
    539378}
    540379
    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 from
    557          * controlD64 to controlD127.  Render node devices go from renderD128
    558          * to renderD192.  The driver takes resize hints via the control device
    559          * on pre-4.10 kernels and on the render device on newer ones.  Try
    560          * both types. */
    561         if (i % 2 == 0)
    562             rc = RTStrPrintf(szPath, sizeof(szPath), "/dev/dri/renderD%u", i / 2 + 128);
    563         else
    564             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 > 2
    577                 || (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 
    602380static const char *getName()
    603381{
     
    616394    (void)fDaemonised;
    617395    int rc;
     396    uint32_t events;
    618397    /* Do not acknowledge the first event we query for to pick up old events,
    619398     * e.g. from before a guest reboot. */
    620399    bool fAck = false;
    621400    struct X11CONTEXT x11Context = { NULL };
    622     x11Connect(&x11Context);
    623     if (x11Context.pDisplay == NULL)
     401    if (!init(&x11Context))
    624402        return VINF_SUCCESS;
    625 
    626 #ifndef USE_XRANDR_BIN
    627     unsigned cHeads;
    628     struct X11VMWRECT aRects[VMW_MAX_HEADS];
    629     if (checkRecentLinuxKernel())
    630         return VINF_SUCCESS;
    631 #else //#ifndef USE_XRANDR_BIN
    632403    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 #endif
    639404
    640405    rc = VbglR3CtlFilterMask(VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST, 0);
     
    656421            RRProviderPropertyNotifyMask |
    657422            RRResourceChangeNotifyMask;
    658     // if (x11Context.hRandRMinor >= 6)
    659     //     eventMask |= RRLeaseNotifyMask;
    660 
    661 
    662423    for (;;)
    663424    {
    664         uint32_t events;
    665425        struct VMMDevDisplayDef aDisplays[VMW_MAX_HEADS];
    666426        uint32_t cDisplaysOut;
    667 
    668427        /* Query the first size without waiting.  This lets us e.g. pick up
    669428         * the last event before a guest reboot when we start again after. */
    670429        rc = VbglR3GetDisplayChangeRequestMulti(VMW_MAX_HEADS, &cDisplaysOut, aDisplays, fAck);
    671430        fAck = true;
    672 
    673431        if (RT_FAILURE(rc))
    674432            VBClLogFatalError("Failed to get display change request, rc=%Rrc\n", rc);
    675433        if (cDisplaysOut > VMW_MAX_HEADS)
    676434            VBClLogFatalError("Display change request contained, rc=%Rrc\n", rc);
    677 #ifndef USE_XRANDR_BIN
    678         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_MAX
    685                                        ? (int16_t)aDisplays[i].xOrigin : 0;
    686                     aRects[cHeads].y =   aDisplays[i].yOrigin < INT16_MAX
    687                                        ? (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 #else
    700435        if (cDisplaysOut > 0)
    701436        {
     
    720455                }
    721456            }
    722 
    723457            /* Create a whole topology and send it to xrandr. */
    724458            struct RANDROUTPUT aOutputs[VMW_MAX_HEADS];
     
    735469            }
    736470            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        }
    774472        do
    775473        {
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette