VirtualBox

Ignore:
Timestamp:
Nov 11, 2021 2:07:41 PM (3 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
148224
Message:

Additions: Linux: VBoxDRMClient: fix resizing issue on kernels <= 4.18, bugref:10134.

This commit fixes resizing issue on kernels older than 4.18 letting VBoxDRMClient to pick
up /dev/dri/controlDxx device instead of /dev/dri/renderDxx one. It also provides a bit of
refactoring and documentation.

File:
1 edited

Legend:

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

    r92215 r92370  
    5050#include <unistd.h>
    5151#include <stdio.h>
    52 
    53 
    54 /** Maximum number of supported screens.  DRM and X11 both limit this to 32. */
    55 /** @todo if this ever changes, dynamically allocate resizeable arrays in the
    56  *  context structure. */
    57 #define VMW_MAX_HEADS 32
    58 
    59 /* VMWare kernel driver control parts definitions. */
     52#include <limits.h>
    6053
    6154#ifdef RT_OS_LINUX
     
    6558#endif
    6659
     60/** Ioctl command to query vmwgfx version information. */
     61#define DRM_IOCTL_VERSION               _IOWR('d', 0x00, struct DRMVERSION)
     62/** Ioctl command to set new screen layout. */
     63#define DRM_IOCTL_VMW_UPDATE_LAYOUT     _IOW('d', 0x40 + 20, struct DRMVMWUPDATELAYOUT)
     64/** A driver name which identifies VMWare driver. */
    6765#define DRM_DRIVER_NAME "vmwgfx"
    68 
    69 /** Counter of how often our daemon has been respawned. */
    70 unsigned      g_cRespawn = 0;
    71 /** Logging verbosity level. */
    72 unsigned      g_cVerbosity = 0;
     66/** VMWare driver compatible version number. On previous versions resizing does not seem work. */
     67#define DRM_DRIVER_VERSION_MAJOR_MIN    (2)
     68#define DRM_DRIVER_VERSION_MINOR_MIN    (10)
     69
     70/** VMWare char device driver minor numbers range. */
     71#define VMW_CONTROL_DEVICE_MINOR_START  (64)
     72#define VMW_RENDER_DEVICE_MINOR_START   (128)
     73#define VMW_RENDER_DEVICE_MINOR_END     (192)
     74
     75/** Maximum number of supported screens.  DRM and X11 both limit this to 32. */
     76/** @todo if this ever changes, dynamically allocate resizeable arrays in the
     77 *  context structure. */
     78#define VMW_MAX_HEADS                   (32)
    7379
    7480/** DRM version structure. */
     
    9096struct DRMVMWRECT
    9197{
    92         int32_t x;
    93         int32_t y;
    94         uint32_t w;
    95         uint32_t h;
     98    int32_t x;
     99    int32_t y;
     100    uint32_t w;
     101    uint32_t h;
    96102};
    97103AssertCompileSize(struct DRMVMWRECT, 16);
    98104
    99 #define DRM_IOCTL_VERSION _IOWR('d', 0x00, struct DRMVERSION)
    100 
    101 struct DRMCONTEXT
    102 {
    103     RTFILE hDevice;
    104 };
    105 
    106 static void drmConnect(struct DRMCONTEXT *pContext)
    107 {
    108     unsigned i;
    109     RTFILE hDevice;
    110 
    111     if (pContext->hDevice != NIL_RTFILE)
    112         VBClLogFatalError("%s called with bad argument\n", __func__);
    113     /* Try to open the SVGA DRM device. */
    114     for (i = 0; i < 128; ++i)
    115     {
    116         char szPath[64];
    117         struct DRMVERSION version;
    118         char szName[sizeof(DRM_DRIVER_NAME)];
    119         int rc;
    120 
    121         /* Control devices for drm graphics driver control devices go from
    122          * controlD64 to controlD127.  Render node devices go from renderD128
    123          * to renderD192.  The driver takes resize hints via the control device
    124          * on pre-4.10 kernels and on the render device on newer ones.  Try
    125          * both types. */
    126         if (i % 2 == 0)
    127             rc = RTStrPrintf(szPath, sizeof(szPath), "/dev/dri/renderD%u", i / 2 + 128);
    128         else
    129             rc = RTStrPrintf(szPath, sizeof(szPath), "/dev/dri/controlD%u", i / 2 + 64);
    130         if (RT_FAILURE(rc))
    131             VBClLogFatalError("RTStrPrintf of device path failed, rc=%Rrc\n", rc);
    132         rc = RTFileOpen(&hDevice, szPath, RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
    133         if (RT_FAILURE(rc))
    134             continue;
    135         RT_ZERO(version);
    136         version.cbName = sizeof(szName);
    137         version.pszName = szName;
    138         rc = RTFileIoCtl(hDevice, DRM_IOCTL_VERSION, &version, sizeof(version), NULL);
    139         if (   RT_SUCCESS(rc)
    140             && !strncmp(szName, DRM_DRIVER_NAME, sizeof(DRM_DRIVER_NAME) - 1)
    141             && (   version.cMajor > 2
    142                 || (version.cMajor == 2 && version.cMinor > 9)))
    143             break;
    144         hDevice = NIL_RTFILE;
    145     }
    146     pContext->hDevice = hDevice;
    147 }
    148 
    149105/** Preferred screen layout information for DRM_VMW_UPDATE_LAYOUT IoCtl.  The
    150106 *  rects argument is a cast pointer to an array of drm_vmw_rect. */
    151 struct DRMVMWUPDATELAYOUT {
    152         uint32_t cOutputs;
    153         uint32_t u32Pad;
    154         uint64_t ptrRects;
     107struct DRMVMWUPDATELAYOUT
     108{
     109    uint32_t cOutputs;
     110    uint32_t u32Pad;
     111    uint64_t ptrRects;
    155112};
    156113AssertCompileSize(struct DRMVMWUPDATELAYOUT, 16);
    157114
    158 #define DRM_IOCTL_VMW_UPDATE_LAYOUT \
    159         _IOW('d', 0x40 + 20, struct DRMVMWUPDATELAYOUT)
    160 
    161 static void drmSendHints(struct DRMCONTEXT *pContext, struct DRMVMWRECT *paRects,
    162                          unsigned cHeads)
     115/** These two parameters are mostly unused. Defined here in order to satisfy linking requirements. */
     116unsigned g_cRespawn = 0;
     117unsigned g_cVerbosity = 0;
     118
     119/**
     120 * Attempts to open DRM device by given path and check if it is
     121 * compatible for screen resize.
     122 *
     123 * @return  DRM device handle on success or NIL_RTFILE otherwise.
     124 * @param   szPathPattern       Path name pattern to the DRM device.
     125 * @param   uInstance           Driver / device instance.
     126 */
     127static RTFILE drmTryDevice(const char *szPathPattern, uint8_t uInstance)
     128{
     129    int rc = VERR_NOT_FOUND;
     130    char szPath[PATH_MAX];
     131    struct DRMVERSION vmwgfxVersion;
     132    RTFILE hDevice = NIL_RTFILE;
     133
     134    RT_ZERO(szPath);
     135    RT_ZERO(vmwgfxVersion);
     136
     137    rc = RTStrPrintf(szPath, sizeof(szPath), szPathPattern, uInstance);
     138    if (RT_SUCCESS(rc))
     139    {
     140        rc = RTFileOpen(&hDevice, szPath, RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
     141        if (RT_SUCCESS(rc))
     142        {
     143            char szVmwgfxDriverName[sizeof(DRM_DRIVER_NAME)];
     144            RT_ZERO(szVmwgfxDriverName);
     145
     146            vmwgfxVersion.cbName = sizeof(szVmwgfxDriverName);
     147            vmwgfxVersion.pszName = szVmwgfxDriverName;
     148
     149            /* Query driver version information and check if it can be used for screen resizing. */
     150            rc = RTFileIoCtl(hDevice, DRM_IOCTL_VERSION, &vmwgfxVersion, sizeof(vmwgfxVersion), NULL);
     151            if (   RT_SUCCESS(rc)
     152                && strncmp(szVmwgfxDriverName, DRM_DRIVER_NAME, sizeof(DRM_DRIVER_NAME) - 1) == 0
     153                && (   vmwgfxVersion.cMajor >= DRM_DRIVER_VERSION_MAJOR_MIN
     154                    || (   vmwgfxVersion.cMajor == DRM_DRIVER_VERSION_MAJOR_MIN
     155                        && vmwgfxVersion.cMinor >= DRM_DRIVER_VERSION_MINOR_MIN)))
     156            {
     157                VBClLogInfo("VBoxDRMClient: found compatible device: %s\n", szPath);
     158            }
     159            else
     160            {
     161                RTFileClose(hDevice);
     162                hDevice = NIL_RTFILE;
     163                rc = VERR_NOT_FOUND;
     164            }
     165        }
     166    }
     167    else
     168    {
     169        VBClLogError("VBoxDRMClient: unable to construct path to DRM device: %Rrc\n", rc);
     170    }
     171
     172    return RT_SUCCESS(rc) ? hDevice : NIL_RTFILE;
     173}
     174
     175/**
     176 * Attempts to find and open DRM device to be used for screen resize.
     177 *
     178 * @return  DRM device handle on success or NIL_RTFILE otherwise.
     179 */
     180static RTFILE drmOpenVmwgfx(void)
     181{
     182    /* Control devices for drm graphics driver control devices go from
     183     * controlD64 to controlD127.  Render node devices go from renderD128
     184     * to renderD192. The driver takes resize hints via the control device
     185     * on pre-4.10 (???) kernels and on the render device on newer ones.
     186     * At first, try to find control device and render one if not found.
     187     */
     188    uint8_t i;
     189    RTFILE hDevice = NIL_RTFILE;
     190
     191    /* Lookup control device. */
     192    for (i = VMW_CONTROL_DEVICE_MINOR_START; i < VMW_RENDER_DEVICE_MINOR_START; i++)
     193    {
     194        hDevice = drmTryDevice("/dev/dri/controlD%u", i);
     195        if (hDevice != NIL_RTFILE)
     196            return hDevice;
     197    }
     198
     199    /* Lookup render device. */
     200    for (i = VMW_RENDER_DEVICE_MINOR_START; i <= VMW_RENDER_DEVICE_MINOR_END; i++)
     201    {
     202        hDevice = drmTryDevice("/dev/dri/renderD%u", i);
     203        if (hDevice != NIL_RTFILE)
     204            return hDevice;
     205    }
     206
     207    VBClLogError("VBoxDRMClient: unable to find DRM device\n");
     208
     209    return hDevice;
     210}
     211
     212static void drmSendHints(RTFILE hDevice, struct DRMVMWRECT *paRects, unsigned cHeads)
    163213{
    164214    uid_t curuid = getuid();
     
    168218    struct DRMVMWUPDATELAYOUT ioctlLayout;
    169219
    170     if (pContext->hDevice == NIL_RTFILE)
    171         VBClLogFatalError("%s bad device argument\n", __func__);
    172220    ioctlLayout.cOutputs = cHeads;
    173221    ioctlLayout.ptrRects = (uint64_t)paRects;
    174     rc = RTFileIoCtl(pContext->hDevice, DRM_IOCTL_VMW_UPDATE_LAYOUT,
     222    rc = RTFileIoCtl(hDevice, DRM_IOCTL_VMW_UPDATE_LAYOUT,
    175223                     &ioctlLayout, sizeof(ioctlLayout), NULL);
    176224    if (RT_FAILURE(rc) && rc != VERR_INVALID_PARAMETER)
     
    182230int main(int argc, char *argv[])
    183231{
    184     int rc = RTR3InitExe(argc, &argv, 0);
    185     if (RT_FAILURE(rc))
    186         return RTMsgInitFailure(rc);
    187     rc = VbglR3InitUser();
    188     if (RT_FAILURE(rc))
    189         VBClLogFatalError("VbglR3InitUser failed: %Rrc", rc);
    190 
    191     struct DRMCONTEXT drmContext = { NIL_RTFILE };
     232    RTFILE hDevice = NIL_RTFILE;
    192233    static struct VMMDevDisplayDef aMonitors[VMW_MAX_HEADS];
    193 
    194234    unsigned cEnabledMonitors;
    195235    /* Do not acknowledge the first event we query for to pick up old events,
     
    201241    RTFILE hPidFile;
    202242
     243    int rc = RTR3InitExe(argc, &argv, 0);
     244    if (RT_FAILURE(rc))
     245        return RTMsgInitFailure(rc);
     246
     247    rc = VbglR3InitUser();
     248    if (RT_FAILURE(rc))
     249        VBClLogFatalError("VbglR3InitUser failed: %Rrc", rc);
     250
    203251    /* Check PID file before attempting to initialize anything. */
    204252    rc = VbglR3PidFile(szPidFile, &hPidFile);
     
    214262    }
    215263
    216     drmConnect(&drmContext);
    217     if (drmContext.hDevice == NIL_RTFILE)
     264    hDevice = drmOpenVmwgfx();
     265    if (hDevice == NIL_RTFILE)
    218266        return VERR_OPEN_FAILED;
     267
    219268    rc = VbglR3CtlFilterMask(VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST, 0);
    220269    if (RT_FAILURE(rc))
     
    288337                printf("Monitor %u: %dx%d, (%d, %d)\n", i, (int)aEnabledMonitors[i].w, (int)aEnabledMonitors[i].h,
    289338                       (int)aEnabledMonitors[i].x, (int)aEnabledMonitors[i].y);
    290             drmSendHints(&drmContext, aEnabledMonitors, cEnabledMonitors);
     339            drmSendHints(hDevice, aEnabledMonitors, cEnabledMonitors);
    291340        }
    292341        do
     
    300349    /** @todo this code never executed since we do not have yet a clean way to exit
    301350     * main event loop above. */
     351
     352    RTFileClose(hDevice);
     353
    302354    VBClLogInfo("VBoxDRMClient: releasing PID file lock\n");
    303355    VbglR3ClosePidFile(szPidFile, hPidFile);
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