VirtualBox

Changeset 89826 in vbox for trunk/src/VBox/Devices/Audio


Ignore:
Timestamp:
Jun 21, 2021 9:41:38 PM (4 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
145283
Message:

DevHda: Partial vista fix. Must avoid chopping up the buffers in an odd manner. bugref:9890

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Audio/DevHdaStream.cpp

    r89638 r89826  
    236236    /* Figure out the BDLE range for this period. */
    237237    uint32_t const idxFirstBdle = idx == 0 ? 0
    238                                 :   pStreamShared->State.aSchedule[idx - 1].idxFirst
    239                                   + pStreamShared->State.aSchedule[idx - 1].cEntries;
     238                                : RT_MIN((uint32_t)(  pStreamShared->State.aSchedule[idx - 1].idxFirst
     239                                                    + pStreamShared->State.aSchedule[idx - 1].cEntries),
     240                                         idxLastBdle);
    240241
    241242    pStreamShared->State.aSchedule[idx].idxFirst = (uint8_t)idxFirstBdle;
     
    340341    uint32_t cbBorrow           = 0;
    341342    uint32_t cbCur              = 0;
     343    uint32_t cbMin              = UINT32_MAX;
    342344    pStreamShared->State.aSchedule[0].idxFirst = 0;
    343345    for (uint32_t i = 0; i < cSegments; i++)
    344346    {
    345347        cbCur += pStreamShared->State.aBdl[i].cb;
     348        if (pStreamShared->State.aBdl[i].cb < cbMin)
     349            cbMin = pStreamShared->State.aBdl[i].cb;
    346350        if (pStreamShared->State.aBdl[i].fFlags & HDA_BDLE_F_IOC)
    347351        {
     
    363367    if (cbCur && cBufferIrqs == 0)
    364368    {
    365         /* No IOC. Split the period in two. */
     369        /*
     370         * No IOC. Vista ends up here, typically with three buffers configured.
     371         *
     372         * The perferred option here is to aim at processing one average BDLE with
     373         * each DMA timer period, since that best matches how we update LPIB at
     374         * present.
     375         *
     376         * The second alternative is to divide the whole span up into 3-4 periods
     377         * to try increase our chances of keeping ahead of the guest.  We may need
     378         * to pick this if there are too few buffer descriptor or they are too small.
     379         *
     380         * However, what we probably should be doing is to do real DMA work whenever
     381         * the guest reads a DMA related register (like LPIB) and just do 3-4 DMA
     382         * timer periods, however we'll be postponing the DMA timer every time we
     383         * return to ring-3 and signal the AIO, so in the end we'd probably not use
     384         * the timer callback at all.  (This is assuming a small shared per-stream
     385         * buffer for keeping the DMA data in and that it's size will force a return
     386         * to ring-3 often enough to keep the AIO thread going at a reasonable rate.)
     387         */
    366388        Assert(cbCur == cbTotal);
    367         cbCur = PDMAudioPropsFloorBytesToFrame(pGuestProps, cbCur / 2);
    368         rc = hdaR3StreamAddScheduleItem(pStreamShared, cbCur, cbMaxPeriod, cSegments, pHostProps, pGuestProps, &cbBorrow);
    369         ASSERT_GUEST_RC_RETURN(rc, rc);
    370 
    371         rc = hdaR3StreamAddScheduleItem(pStreamShared, cbTotal - cbCur, cbMaxPeriod, cSegments,
    372                                         pHostProps, pGuestProps, &cbBorrow);
    373         ASSERT_GUEST_RC_RETURN(rc, rc);
     389
     390        /* Match the BDLEs 1:1 if there are 3 or more and that the smallest one
     391           is at least 5ms big. */
     392        if (cSegments >= 3 && PDMAudioPropsBytesToMilli(pGuestProps, cbMin) >= 5 /*ms*/)
     393        {
     394            for (uint32_t i = 0; i < cSegments; i++)
     395            {
     396                rc = hdaR3StreamAddScheduleItem(pStreamShared, pStreamShared->State.aBdl[i].cb, cbMaxPeriod,
     397                                                i, pHostProps, pGuestProps, &cbBorrow);
     398                ASSERT_GUEST_RC_RETURN(rc, rc);
     399            }
     400        }
     401        /* Otherwise, just divide the work into 3 or 4 portions and hope for the best.
     402           It seems, though, that this only really work for windows vista if we avoid
     403           working accross buffer lines.  */
     404        /** @todo This can be simplified/relaxed/uncluttered if we do DMA work when LPIB
     405         * is read, assuming ofc that LPIB is read before each buffer update. */
     406        else
     407        {
     408            uint32_t const cPeriods = cSegments != 3 && PDMAudioPropsBytesToMilli(pGuestProps, cbCur) >= 4 * 5 /*ms*/
     409                                    ? 4 : cSegments != 2 ? 3 : 2;
     410            uint32_t const cbPeriod = PDMAudioPropsFloorBytesToFrame(pGuestProps, cbCur / cPeriods);
     411            uint32_t       iBdle    = 0;
     412            uint32_t       offBdle  = 0;
     413            for (uint32_t iPeriod = 0; iPeriod < cPeriods; iPeriod++)
     414            {
     415                if (iPeriod + 1 < cPeriods)
     416                {
     417                    offBdle += cbPeriod;
     418                    while (iBdle < cSegments && offBdle >= pStreamShared->State.aBdl[iBdle].cb)
     419                        offBdle -= pStreamShared->State.aBdl[iBdle++].cb;
     420                    rc = hdaR3StreamAddScheduleItem(pStreamShared, cbPeriod, cbMaxPeriod, offBdle != 0 ? iBdle : iBdle - 1,
     421                                                    pHostProps, pGuestProps, &cbBorrow);
     422                }
     423                else
     424                    rc = hdaR3StreamAddScheduleItem(pStreamShared, cbCur - iPeriod * cbPeriod, cbMaxPeriod, cSegments - 1,
     425                                                    pHostProps, pGuestProps, &cbBorrow);
     426                ASSERT_GUEST_RC_RETURN(rc, rc);
     427            }
     428
     429        }
    374430        Assert(cbBorrow == 0);
    375431    }
     
    9991055{
    10001056    AssertPtrReturnVoid(pStreamShared);
    1001     AssertReturnVoid   (uLPIB <= pStreamShared->u32CBL); /* Make sure that we don't go out-of-bounds. */
     1057    AssertMsgStmt(uLPIB <= pStreamShared->u32CBL, ("%#x\n", uLPIB), uLPIB = pStreamShared->u32CBL);
    10021058
    10031059    Log3Func(("[SD%RU8] LPIB=%RU32 (DMA Position Buffer Enabled: %RTbool)\n",  pStreamShared->u8SD, uLPIB, pThis->fDMAPosition));
     
    10331089        uint32_t const uCBL = pStreamShared->u32CBL;
    10341090        if (uCBL) /* paranoia */
    1035             hdaR3StreamSetPositionAbs(pStreamShared, pDevIns, pThis,
    1036                                       (HDA_STREAM_REG(pThis, LPIB, pStreamShared->u8SD) + cbToAdd) % uCBL);
     1091        {
     1092            uint32_t uNewLpid = HDA_STREAM_REG(pThis, LPIB, pStreamShared->u8SD) + cbToAdd;
     1093#if 1 /** @todo r=bird: this is wrong according to the spec */
     1094            uNewLpid %= uCBL;
     1095#else
     1096            /* The spec says it goes to CBL then wraps arpimd to 1, not back to zero. See 3.3.37.  */
     1097            if (uNewLpid > uCBL)
     1098                uNewLpid %= uCBL;
     1099#endif
     1100            hdaR3StreamSetPositionAbs(pStreamShared, pDevIns, pThis, uNewLpid);
     1101        }
    10371102    }
    10381103}
     
    12641329         *
    12651330         * Do this as accurate and close to the actual data transfer as possible.
    1266          * All guetsts rely on this, depending on the mechanism they use (LPIB register or DMA counters).
     1331         * All guests rely on this, depending on the mechanism they use (LPIB register or DMA counters).
    12671332         *
    12681333         * Note for Windows 10: The OS' driver is *very* picky about *when* the (DMA) positions get updated!
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