VirtualBox

Ignore:
Timestamp:
Dec 4, 2023 3:31:48 PM (16 months ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
160596
Message:

Additions: X11/Wayland: Add host resize events suppression in VBoxDRMClient, bugref:10134.

File:
1 edited

Legend:

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

    r98103 r102453  
    111111#include <iprt/asm.h>
    112112#include <iprt/localipc.h>
     113#include <iprt/timer.h>
    113114
    114115#include <unistd.h>
     
    151152/** Maximum number of simultaneous IPC client connections. */
    152153#define DRM_IPC_SERVER_CONNECTIONS_MAX  (16)
     154/** Interval between attempts to send resize events to DRM stack. */
     155#define DRM_RESIZE_INTERVAL_MS          (250)
    153156
    154157/** IPC client connections counter. */
     
    210213static RTCRITSECT g_monitorPositionsCritSect;
    211214
     215/** Resize events suppression.
     216 *
     217 *  We tend to suppress incoming resizing events from host. Instead of
     218 *  applying them immediately to Linux DRM stack, we keep them and apply
     219 *  in recurring timer callback. This structure collects all the necessary
     220 * components to implement events suppression. */
     221static struct VBOX_DRM_SUPPRESSION
     222{
     223    /** Protection for concurrent access from host events loop and
     224     *  suppression timer contexts. */
     225    RTCRITSECT critSect;
     226
     227    /** Recurring timer which is used in order to push resize events
     228     *  into DRM stack. */
     229    PRTTIMER pResizeSuppressionTimer;
     230
     231    /** Resize parameters from the last host event: coordinates. */
     232    VMMDevDisplayDef aDisplaysIn[VBOX_DRMIPC_MONITORS_MAX];
     233
     234    /** Resize parameters from the last host event: number of displays. */
     235    uint32_t cDisplaysIn;
     236
     237    /** Flag to indicate that new events were suppressed since last
     238     *  time when we sent data to DRM stack. */
     239    bool fHaveSuppressedEvents;
     240} g_vboxDrmSuppression;
     241
    212242/** Counter of how often our daemon has been re-spawned. */
    213243unsigned g_cRespawn = 0;
     
    621651}
    622652
     653/**
     654 * Suppress incoming resize events from host.
     655 *
     656 * This function will put last resize event data into suppression
     657 * cache. This data will later be picked up by timer callback and
     658 * pushed into DRM stack.
     659 *
     660 * @returns IPRT status code.
     661 * @param   paDisplaysIn    Display resize data.
     662 * @param   cDisplaysIn     Number of displays.
     663 */
     664static int vbDrmResizeSuppress(VMMDevDisplayDef *paDisplaysIn, uint32_t cDisplaysIn)
     665{
     666    int rc;
     667
     668    Assert((sizeof(VMMDevDisplayDef) * cDisplaysIn) <= sizeof(g_vboxDrmSuppression.aDisplaysIn));
     669
     670    rc = RTCritSectEnter(&g_vboxDrmSuppression.critSect);
     671    if (RT_FAILURE(rc))
     672    {
     673        VBClLogError("unable to lock suppression data cache, rc=%Rrc\n", rc);
     674        return rc;
     675    }
     676
     677    memcpy(g_vboxDrmSuppression.aDisplaysIn, paDisplaysIn, sizeof(VMMDevDisplayDef) * cDisplaysIn);
     678    g_vboxDrmSuppression.cDisplaysIn = cDisplaysIn;
     679    g_vboxDrmSuppression.fHaveSuppressedEvents = true;
     680
     681    int rc2 = RTCritSectLeave(&g_vboxDrmSuppression.critSect);
     682    if (RT_FAILURE(rc2))
     683        VBClLogError("unable to unlock suppression data cache, rc=%Rrc\n", rc);
     684
     685    if (RT_SUCCESS(rc))
     686        rc = rc2;
     687
     688    return rc;
     689}
     690
     691/** Recurring timer callback to push display resize events into DRM stack.
     692 *
     693 * @param   pTimer  IPRT timer structure (unused).
     694 * @param   pvUser  User data (unused).
     695 * @param   iTick   Timer tick data (unused).
     696 */
     697static DECLCALLBACK(void) vbDrmResizeSuppressionTimerCb(PRTTIMER pTimer, void *pvUser, uint64_t iTick)
     698{
     699    int rc;
     700
     701    RT_NOREF(pTimer, pvUser, iTick);
     702
     703    rc = RTCritSectEnter(&g_vboxDrmSuppression.critSect);
     704    if (RT_FAILURE(rc))
     705    {
     706        VBClLogError("unable to lock suppression data cache, rc=%Rrc\n", rc);
     707        return;
     708    }
     709
     710    if (g_vboxDrmSuppression.fHaveSuppressedEvents)
     711    {
     712        rc = vbDrmPushScreenLayout(g_vboxDrmSuppression.aDisplaysIn, g_vboxDrmSuppression.cDisplaysIn, false, true);
     713        if (RT_FAILURE(rc))
     714            VBClLogError("Failed to push display change as requested by host, rc=%Rrc\n", rc);
     715
     716        g_vboxDrmSuppression.fHaveSuppressedEvents = false;
     717    }
     718
     719    int rc2 = RTCritSectLeave(&g_vboxDrmSuppression.critSect);
     720    if (RT_FAILURE(rc2))
     721        VBClLogError("unable to unlock suppression data cache, rc=%Rrc\n", rc);
     722}
     723
     724/**
     725 * Initialize DRM events suppression data.
     726 *
     727 * @returns IPRT status code.
     728 * @param   pSuppression    Pointer to suppression data.
     729 */
     730static int vbDrmSuppressionInit(struct VBOX_DRM_SUPPRESSION *pSuppression)
     731{
     732    int rc;
     733
     734    RT_BZERO(pSuppression, sizeof(*pSuppression));
     735
     736    rc = RTCritSectInit(&pSuppression->critSect);
     737    if (RT_SUCCESS(rc))
     738    {
     739        rc = RTTimerCreate(&pSuppression->pResizeSuppressionTimer, DRM_RESIZE_INTERVAL_MS, vbDrmResizeSuppressionTimerCb, NULL);
     740        if (RT_SUCCESS(rc))
     741            VBClLogInfo("starting deferred resize events delivery\n");
     742        else
     743            VBClLogError("unable to enable deferred resize events delivery: no timer, rc=%Rrc\n", rc);
     744    }
     745    else
     746        VBClLogError("unable to enable deferred resize events delivery: no critsect, rc=%Rrc\n", rc);
     747
     748    return rc;
     749}
     750
     751/**
     752 * Destroy DRM events suppression data.
     753 *
     754 * @returns IPRT status code.
     755 * @param   pSuppression    Pointer to suppression data.
     756 */
     757static int vbDrmSuppressionDestroy(struct VBOX_DRM_SUPPRESSION *pSuppression)
     758{
     759    int rc;
     760
     761    rc = RTTimerDestroy(pSuppression->pResizeSuppressionTimer);
     762    if (RT_SUCCESS(rc))
     763    {
     764        rc = RTCritSectDelete(&pSuppression->critSect);
     765        if (RT_FAILURE(rc))
     766            VBClLogError("unable to destroy suppression critsect, rc=%Rrc\n", rc);
     767    }
     768    else
     769        VBClLogError("unable to destroy suppression timer, rc=%Rrc\n", rc);
     770
     771    return rc;
     772}
     773
    623774/** Worker thread for resize task. */
    624775static DECLCALLBACK(int) vbDrmResizeWorker(RTTHREAD ThreadSelf, void *pvUser)
     
    648799        if (RT_SUCCESS(rc))
    649800        {
    650             rc = vbDrmPushScreenLayout(aDisplaysIn, cDisplaysIn, false, true);
     801            rc = vbDrmResizeSuppress(aDisplaysIn, cDisplaysIn);
    651802            if (RT_FAILURE(rc))
    652803                VBClLogError("Failed to push display change as requested by host, rc=%Rrc\n", rc);
     
    11191270    }
    11201271
    1121     /* Set flag for the thread which serves incomming IPC connections. */
     1272    /* Set flag for the thread which serves incoming IPC connections. */
    11221273    ASMAtomicWriteBool(&g_fDrmIpcRestricted, fRestrict);
    11231274}
     
    12991450    }
    13001451
     1452    rc = vbDrmSuppressionInit(&g_vboxDrmSuppression);
     1453    if (RT_FAILURE(rc))
     1454        return RTEXITCODE_FAILURE;
     1455
    13011456    /* Instantiate IPC server for VBoxClient service communication. */
    13021457    rc = RTLocalIpcServerCreate(&hIpcServer, VBOX_DRMIPC_SERVER_NAME, 0);
     
    13511506        VBClLogError("unable to stop IPC server,  rc=%Rrc\n", rc);
    13521507
     1508    rc2 = vbDrmSuppressionDestroy(&g_vboxDrmSuppression);
     1509    if (RT_FAILURE(rc2))
     1510        VBClLogError("unable to destroy suppression data, rc=%Rrc\n", rc2);
     1511
    13531512    rc2 = RTCritSectDelete(&g_monitorPositionsCritSect);
    13541513    if (RT_FAILURE(rc2))
Note: See TracChangeset for help on using the changeset viewer.

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