VirtualBox

Changeset 87567 in vbox for trunk/src/VBox/Devices


Ignore:
Timestamp:
Feb 3, 2021 2:25:29 PM (4 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
142594
Message:

Audio/HDA: More timing-related fixes for Windows guests. This is a risky change and needs more testing / verification on other guests. Only got limited testing for Win10 AU / Win10 20H2 and Ubuntu 20.10 guests so far. ticketoem2ref:36

Location:
trunk/src/VBox/Devices/Audio
Files:
4 edited

Legend:

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

    r87464 r87567  
    13431343
    13441344                    uint64_t const tsNow = PDMDevHlpTimerGet(pDevIns, pStreamShared->hTimer);
    1345                     rc2 = hdaR3TimerSet(pDevIns, pStreamShared, tsNow + pStreamShared->State.cTransferTicks, false /* fForce */, tsNow);
     1345                    rc2 = hdaR3TimerSet(pDevIns, pStreamShared, tsNow + pStreamShared->State.cTransferTicks, true /* fForce */, tsNow);
    13461346                    AssertRC(rc2);
    13471347                }
     
    14481448        Assert(tsNow >= pStreamShared->State.tsTransferLast);
    14491449
    1450         const uint64_t cTicksElapsed     = tsNow - pStreamShared->State.tsTransferLast;
    1451 # ifdef LOG_ENABLED
    1452         const uint64_t cTicksTransferred = pStreamShared->State.cbTransferProcessed * pStreamShared->State.cTicksPerByte;
    1453 # endif
    1454 
    1455         Log3Func(("[SD%RU8] cTicksElapsed=%RU64, cTicksTransferred=%RU64, cTicksToNext=%RU64\n",
    1456                   uSD, cTicksElapsed, cTicksTransferred, cTicksToNext));
    1457 
    1458         Log3Func(("[SD%RU8] cbTransferProcessed=%RU32, cbTransferChunk=%RU32, cbTransferSize=%RU32\n", uSD,
    1459                   pStreamShared->State.cbTransferProcessed, pStreamShared->State.cbTransferChunk, pStreamShared->State.cbTransferSize));
     1450        const uint64_t cTicksElapsed = tsNow - pStreamShared->State.tsTransferLast;
     1451
     1452        Log3Func(("[SD%RU8] cTicksElapsed=%RU64, cTicksToNext=%RU64\n",
     1453                  uSD, cTicksElapsed, cTicksToNext));
    14601454
    14611455        if (cTicksElapsed <= cTicksToNext)
     
    14691463                             uSD, cTicksToNext / 1000,  cTicksElapsed / 1000, pStreamShared->State.cTransferPendingInterrupts));
    14701464
    1471             cTicksToNext = 0;
     1465            cTicksToNext = pStreamShared->State.cbTransferSize * pStreamShared->State.cTicksPerByte;
    14721466        }
    14731467
     
    14751469
    14761470        /* Reset processed data counter. */
    1477         pStreamShared->State.cbTransferProcessed = 0;
    1478         pStreamShared->State.tsTransferNext      = tsNow + cTicksToNext;
     1471        pStreamShared->State.tsTransferNext = tsNow + cTicksToNext;
    14791472
    14801473        /* Only re-arm the timer if there were pending transfer interrupts left
     
    14861479
    14871480            /* Re-arm the timer. */
    1488             LogFunc(("Timer set SD%RU8\n", uSD));
     1481            LogFunc(("[SD%RU8] Timer set\n", uSD));
    14891482            hdaR3TimerSet(pDevIns, pStreamShared, tsNow + cTicksToNext,
    14901483                          true /* fForce - we just set tsTransferNext*/, 0 /*tsNow*/);
     
    39183911        {
    39193912            /* Paranoia. */
    3920             AssertLogRelMsgReturn(cbCircBufSize <= _1M,
     3913            AssertLogRelMsgReturn(cbCircBufSize <= _32M,
    39213914                                  ("HDA: Saved state contains bogus DMA buffer size (%RU32) for stream #%RU8",
    39223915                                   cbCircBufSize, idStream),
     
    45994592
    46004593    /* Note: Error checking of this value happens in hdaR3StreamSetUp(). */
    4601     int rc = pHlp->pfnCFGMQueryU16Def(pCfg, "BufSizeInMs", &pThis->cbCircBufInMs, RT_MS_1SEC /* Default value, if not set. */);
     4594    int rc = pHlp->pfnCFGMQueryU16Def(pCfg, "BufSizeInMs", &pThis->cbCircBufInMs, RT_MS_10SEC /* Default value, if not set. */);
    46024595    if (RT_FAILURE(rc))
    46034596        return PDMDEV_SET_ERROR(pDevIns, rc,
     
    46054598
    46064599    /* Note: Error checking of this value happens in hdaR3StreamSetUp(). */
    4607     rc = pHlp->pfnCFGMQueryU16Def(pCfg, "BufSizeOutMs", &pThis->cbCircBufOutMs, RT_MS_1SEC /* Default value, if not set. */);
     4600    rc = pHlp->pfnCFGMQueryU16Def(pCfg, "BufSizeOutMs", &pThis->cbCircBufOutMs, RT_MS_10SEC /* Default value, if not set. */);
    46084601    if (RT_FAILURE(rc))
    46094602        return PDMDEV_SET_ERROR(pDevIns, rc,
  • trunk/src/VBox/Devices/Audio/DevHDA.h

    r87436 r87567  
    3333#include "HDAStreamPeriod.h"
    3434
    35 
     35#ifdef DEBUG_andy
     36/** Enables strict mode, which checks for stuff which isn't supposed to happen.
     37 *  Be prepared for assertions coming in! */
     38# define HDA_STRICT
     39#endif
    3640
    3741/**
  • trunk/src/VBox/Devices/Audio/HDAStream.cpp

    r87465 r87567  
    3030#include <VBox/vmm/pdmaudioifs.h>
    3131
     32#include <math.h> /* Needed for round(). */
     33
    3234#include "DrvAudio.h"
    3335
     
    4143*   Internal Functions                                                                                                           *
    4244*********************************************************************************************************************************/
    43 static void hdaR3StreamSetPosition(PHDASTREAM pStreamShared, PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t u32LPIB);
     45static void hdaR3StreamSetPositionAbs(PHDASTREAM pStreamShared, PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t uLPIB);
    4446
    4547static int  hdaR3StreamAsyncIODestroy(PHDASTREAMR3 pStreamR3);
     
    8284    rc = hdaR3StreamPeriodCreate(&pStreamShared->State.Period);
    8385    AssertRCReturn(rc, rc);
    84 
    85     pStreamShared->State.tsLastUpdateNs = 0;
    8686
    8787#ifdef DEBUG
     
    361361    }
    362362
    363     const uint32_t cbCircBufDefault = DrvAudioHlpMilliToBytes(RT_MS_1SEC, &pCfg->Props);
     363    const uint32_t cbCircBufDefault = DrvAudioHlpMilliToBytes(RT_MS_10SEC, &pCfg->Props);
    364364
    365365    uint32_t cbCircBuf = DrvAudioHlpMilliToBytes(  hdaGetDirFromSD(uSD) == PDMAUDIODIR_IN
     
    506506         */
    507507
    508         /* Calculate the fragment size the guest OS expects interrupt delivery at. */
    509         pStreamShared->State.cbTransferSize = pStreamShared->u32CBL / cFragments;
    510         Assert(pStreamShared->State.cbTransferSize);
    511         Assert(pStreamShared->State.cbTransferSize % pStreamR3->State.Mapping.cbFrameSize == 0);
     508        /* Prevent division by zero. */
     509        ASSERT_GUEST_LOGREL_MSG_STMT(pStreamShared->State.uTimerHz,
     510                                     ("Timer Hz rate for stream #%RU8 is invalid\n", uSD),
     511                                     pStreamShared->State.uTimerHz = HDA_TIMER_HZ_DEFAULT);
     512        /*
     513         * Calculate the fragment size the guest OS expects interrupt delivery at.
     514         *
     515         * Guests also expect a very extact DMA timing for reading / writing audio data, so we run on a constant
     516         * (virtual) rate which we expose to the guest.
     517         *
     518         * Data rate examples:
     519         *   * Windows 10 @ 44,1kHz / 16-bit stereo
     520         *      * Default mode: 448 audio frames (~10.15ms) = 1792 byte / ~10ms.
     521         *      * Fast mode:    128 audio frames (~ 2.90ms) =  512 byte / ~3ms.
     522         */
     523        pStreamShared->State.cbTransferSize
     524            = (pStreamShared->State.Cfg.Props.uHz * pStreamR3->State.Mapping.cbFrameSize) / pStreamShared->State.uTimerHz;
    512525        ASSERT_GUEST_LOGREL_MSG_STMT(pStreamShared->State.cbTransferSize,
    513526                                     ("Transfer size for stream #%RU8 is invalid\n", uSD), rc = VERR_INVALID_PARAMETER);
    514527        if (RT_SUCCESS(rc))
    515528        {
    516             /* Calculate the bytes we need to transfer to / from the stream's DMA per iteration.
    517              * This is bound to the device's Hz rate and thus to the (virtual) timing the device expects. */
    518             pStreamShared->State.cbTransferChunk = (pStreamShared->State.Cfg.Props.uHz / pStreamShared->State.uTimerHz) * pStreamR3->State.Mapping.cbFrameSize;
    519             Assert(pStreamShared->State.cbTransferChunk);
    520             Assert(pStreamShared->State.cbTransferChunk % pStreamR3->State.Mapping.cbFrameSize == 0);
     529            /*
     530             * Calculate the bytes we need to transfer to / from the stream's DMA per iteration.
     531             * This is bound to the device's Hz rate and thus to the (virtual) timing the device expects.
     532             *
     533             * As we don't do chunked transfers the moment, the chunk size equals the overall transfer size.
     534             */
     535            pStreamShared->State.cbTransferChunk = pStreamShared->State.cbTransferSize;
    521536            ASSERT_GUEST_LOGREL_MSG_STMT(pStreamShared->State.cbTransferChunk,
    522537                                         ("Transfer chunk for stream #%RU8 is invalid\n", uSD),
     
    525540            {
    526541                /* Make sure that the transfer chunk does not exceed the overall transfer size. */
    527                 if (pStreamShared->State.cbTransferChunk > pStreamShared->State.cbTransferSize)
    528                     pStreamShared->State.cbTransferChunk = pStreamShared->State.cbTransferSize;
    529 
    530                 const uint64_t cTicksPerHz = PDMDevHlpTimerGetFreq(pDevIns, pStreamShared->hTimer) / pStreamShared->State.uTimerHz;
     542                AssertStmt(pStreamShared->State.cbTransferChunk <= pStreamShared->State.cbTransferSize,
     543                           pStreamShared->State.cbTransferChunk = pStreamShared->State.cbTransferSize);
     544
     545                const uint64_t uTimerFreq = PDMDevHlpTimerGetFreq(pDevIns, pStreamShared->hTimer);
     546
     547                const double cTicksPerHz   = uTimerFreq  / pStreamShared->State.uTimerHz;
     548                const double cTicksPerByte = cTicksPerHz / (double)pStreamShared->State.cbTransferChunk;
    531549
    532550                /* Calculate the timer ticks per byte for this stream. */
    533                 pStreamShared->State.cTicksPerByte = cTicksPerHz / pStreamShared->State.cbTransferChunk;
     551                pStreamShared->State.cTicksPerByte = round(cTicksPerByte); /** @todo r=andy Do we have rounding in IPRT? */
    534552                Assert(pStreamShared->State.cTicksPerByte);
    535553
     554                const double cTransferTicks = pStreamShared->State.cbTransferChunk * cTicksPerByte;
     555
    536556                /* Calculate timer ticks per transfer. */
    537                 pStreamShared->State.cTransferTicks = pStreamShared->State.cbTransferChunk * pStreamShared->State.cTicksPerByte;
     557                pStreamShared->State.cTransferTicks = round(cTransferTicks);
    538558                Assert(pStreamShared->State.cTransferTicks);
    539559
    540                 LogFunc(("[SD%RU8] Timer %uHz (%RU64 ticks per Hz), cTicksPerByte=%RU64, cbTransferChunk=%RU32, " \
    541                          "cTransferTicks=%RU64, cbTransferSize=%RU32\n",
    542                          uSD, pStreamShared->State.uTimerHz, cTicksPerHz, pStreamShared->State.cTicksPerByte,
    543                          pStreamShared->State.cbTransferChunk, pStreamShared->State.cTransferTicks, pStreamShared->State.cbTransferSize));
     560                LogRel2(("HDA: Stream #%RU8 is using %uHz device timer (%RU64 virtual ticks / Hz), stream Hz=%RU32, "
     561                         "cTicksPerByte=%RU64, cTransferTicks=%RU64 -> cbTransferChunk=%RU32 (%RU64ms), cbTransferSize=%RU32 (%RU64ms)\n",
     562                         uSD, pStreamShared->State.uTimerHz, (uint64_t)cTicksPerHz, pStreamShared->State.Cfg.Props.uHz,
     563                         pStreamShared->State.cTicksPerByte, pStreamShared->State.cTransferTicks,
     564                         pStreamShared->State.cbTransferChunk, DrvAudioHlpBytesToMilli(pStreamShared->State.cbTransferChunk, &pCfg->Props),
     565                         pStreamShared->State.cbTransferSize,  DrvAudioHlpBytesToMilli(pStreamShared->State.cbTransferSize,  &pCfg->Props)));
    544566
    545567                /* Make sure to also update the stream's DMA counter (based on its current LPIB value). */
    546                 hdaR3StreamSetPosition(pStreamShared, pDevIns, pThis, HDA_STREAM_REG(pThis, LPIB, uSD));
     568                hdaR3StreamSetPositionAbs(pStreamShared, pDevIns, pThis, HDA_STREAM_REG(pThis, LPIB, uSD));
    547569
    548570#ifdef LOG_ENABLED
     
    613635
    614636    /* Reset transfer stuff. */
    615     pStreamShared->State.cbTransferProcessed        = 0;
    616637    pStreamShared->State.cTransferPendingInterrupts = 0;
    617638    pStreamShared->State.tsTransferLast = 0;
     
    715736}
    716737
     738#if 0 /* Not used atm. */
    717739static uint32_t hdaR3StreamGetPosition(PHDASTATE pThis, PHDASTREAM pStreamShared)
    718740{
    719741    return HDA_STREAM_REG(pThis, LPIB, pStreamShared->u8SD);
    720742}
     743#endif
    721744
    722745/*
    723746 * Updates an HDA stream's current read or write buffer position (depending on the stream type) by
    724  * updating its associated LPIB register and DMA position buffer (if enabled).
     747 * setting its associated LPIB register and DMA position buffer (if enabled) to an absolute value.
    725748 *
    726749 * @param   pStreamShared       HDA stream to update read / write position for (shared).
    727750 * @param   pDevIns             The device instance.
    728751 * @param   pThis               The shared HDA device state.
    729  * @param   u32LPIB             Absolute position (in bytes) to set current read / write position to.
    730  */
    731 static void hdaR3StreamSetPosition(PHDASTREAM pStreamShared, PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t u32LPIB)
     752 * @param   uLPIB               Absolute position (in bytes) to set current read / write position to.
     753 */
     754static void hdaR3StreamSetPositionAbs(PHDASTREAM pStreamShared, PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t uLPIB)
    732755{
    733756    AssertPtrReturnVoid(pStreamShared);
    734 
    735     Log3Func(("[SD%RU8] LPIB=%RU32 (DMA Position Buffer Enabled: %RTbool)\n",  pStreamShared->u8SD, u32LPIB, pThis->fDMAPosition));
     757    AssertReturnVoid   (uLPIB <= pStreamShared->u32CBL); /* Make sure that we don't go out-of-bounds. */
     758
     759    Log3Func(("[SD%RU8] LPIB=%RU32 (DMA Position Buffer Enabled: %RTbool)\n",  pStreamShared->u8SD, uLPIB, pThis->fDMAPosition));
    736760
    737761    /* Update LPIB in any case. */
    738     HDA_STREAM_REG(pThis, LPIB, pStreamShared->u8SD) = u32LPIB;
     762    HDA_STREAM_REG(pThis, LPIB, pStreamShared->u8SD) = uLPIB;
    739763
    740764    /* Do we need to tell the current DMA position? */
     
    743767        int rc2 = PDMDevHlpPCIPhysWrite(pDevIns,
    744768                                        pThis->u64DPBase + (pStreamShared->u8SD * 2 * sizeof(uint32_t)),
    745                                         (void *)&u32LPIB, sizeof(uint32_t));
     769                                        (void *)&uLPIB, sizeof(uint32_t));
    746770        AssertRC(rc2);
    747771    }
     772}
     773
     774/*
     775 * Updates an HDA stream's current read or write buffer position (depending on the stream type) by
     776 * adding a value to its associated LPIB register and DMA position buffer (if enabled).
     777 *
     778 * @note    Handles automatic CBL wrap-around.
     779 *
     780 * @param   pStreamShared       HDA stream to update read / write position for (shared).
     781 * @param   pDevIns             The device instance.
     782 * @param   pThis               The shared HDA device state.
     783 * @param   uToAdd              Position (in bytes) to add to the current read / write position.
     784 */
     785void hdaR3StreamSetPositionAdd(PHDASTREAM pStreamShared, PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t uToAdd)
     786{
     787    if (!uToAdd) /* No need to update anything if 0. */
     788        return;
     789
     790    hdaR3StreamSetPositionAbs(pStreamShared, pDevIns, pThis,
     791                              (HDA_STREAM_REG(pThis, LPIB, pStreamShared->u8SD) + uToAdd) % pStreamShared->u32CBL);
    748792}
    749793
     
    941985    if (pcbRead)
    942986        *pcbRead = cbReadTotal;
     987
     988    return rc;
     989}
     990
     991/*
     992 * Reads DMA data from a given HDA output stream.
     993 *
     994 * @return  IPRT status code.
     995 * @param   pDevIns             The device instance.
     996 * @param   pThis               The shared HDA device state (for stats).
     997 * @param   pStreamShared       HDA output stream to read DMA data from - shared bits.
     998 * @param   pStreamR3           HDA output stream to read DMA data from - shared ring-3.
     999 * @param   pvBuf               Where to store the read data.
     1000 * @param   cbBuf               How much to read in bytes.
     1001 * @param   pcbRead             Returns read bytes from DMA. Optional.
     1002 */
     1003int hdaR3DMARead2(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3,
     1004                  void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead)
     1005{
     1006    RT_NOREF(pThis);
     1007    PHDABDLE pBDLE = &pStreamShared->State.BDLE;
     1008
     1009    int rc = VINF_SUCCESS;
     1010
     1011    uint32_t cbReadTotal = 0;
     1012    uint32_t cbLeft      = RT_MIN(cbBuf, pBDLE->Desc.u32BufSize - pBDLE->State.u32BufOff);
     1013
     1014# ifdef HDA_DEBUG_SILENCE
     1015    uint64_t   csSilence = 0;
     1016
     1017    pStreamR3->Dbg.cSilenceThreshold = 100;
     1018    pStreamR3->Dbg.cbSilenceReadMin  = _1M;
     1019# endif
     1020
     1021    RTGCPHYS GCPhysChunk = pBDLE->Desc.u64BufAddr + pBDLE->State.u32BufOff;
     1022
     1023    while (cbLeft)
     1024    {
     1025        uint32_t cbChunk = RT_MIN(cbLeft, pStreamShared->u8FIFOS);
     1026
     1027        rc = PDMDevHlpPhysRead(pDevIns, GCPhysChunk, (uint8_t *)pvBuf + cbReadTotal, cbChunk);
     1028        AssertRCBreak(rc);
     1029
     1030# ifdef HDA_DEBUG_SILENCE
     1031        uint16_t *pu16Buf = (uint16_t *)pvBuf;
     1032        for (size_t i = 0; i < cbChunk / sizeof(uint16_t); i++)
     1033        {
     1034            if (*pu16Buf == 0)
     1035                csSilence++;
     1036            else
     1037                break;
     1038            pu16Buf++;
     1039        }
     1040# endif
     1041
     1042        /*
     1043         * Update the stream's current position.
     1044         * Do this as accurate and close to the actual data transfer as possible.
     1045         * All guetsts rely on this, depending on the mechanism they use (LPIB register or DMA counters).
     1046         */
     1047        hdaR3StreamSetPositionAdd(pStreamShared, pDevIns, pThis, /* cbChunk */ 0);
     1048
     1049        if (RT_LIKELY(!pStreamR3->Dbg.Runtime.fEnabled))
     1050        { /* likely */ }
     1051        else
     1052            DrvAudioHlpFileWrite(pStreamR3->Dbg.Runtime.pFileDMARaw, (uint8_t *)pvBuf + cbReadTotal, cbChunk, 0 /* fFlags */);
     1053
     1054        STAM_COUNTER_ADD(&pThis->StatBytesRead, cbChunk);
     1055
     1056        /* advance */
     1057        Assert(cbLeft    >= cbChunk);
     1058        GCPhysChunk       = (GCPhysChunk + cbChunk) % pBDLE->Desc.u32BufSize;
     1059        cbReadTotal      += cbChunk;
     1060        cbLeft           -= cbChunk;
     1061    }
     1062
     1063# ifdef HDA_DEBUG_SILENCE
     1064    if (csSilence)
     1065        pStreamR3->Dbg.csSilence += csSilence;
     1066
     1067    if (   csSilence == 0
     1068        && pStreamR3->Dbg.csSilence   >  pStreamR3->Dbg.cSilenceThreshold
     1069        && pStreamR3->Dbg.cbReadTotal >= pStreamR3->Dbg.cbSilenceReadMin)
     1070    {
     1071        LogFunc(("Silent block detected: %RU64 audio samples\n", pStreamR3->Dbg.csSilence));
     1072        pStreamR3->Dbg.csSilence = 0;
     1073    }
     1074# endif
     1075
     1076    if (RT_SUCCESS(rc))
     1077    {
     1078        if (pcbRead)
     1079            *pcbRead = cbReadTotal;
     1080    }
    9431081
    9441082    return rc;
     
    9661104                               PHDASTREAMR3 pStreamR3, uint32_t cbToProcessMax, bool fInTimer)
    9671105{
     1106    LogFlowFuncEnter();
     1107
    9681108    uint8_t const uSD = pStreamShared->u8SD;
    9691109    hdaR3StreamLock(pStreamR3);
     
    9741114    bool fProceed = true;
    9751115
    976     /* Stream not running? */
     1116    /* Stream not running (anymore)? */
    9771117    if (!pStreamShared->State.fRunning)
    9781118    {
    979         Log3Func(("[SD%RU8] Not running\n", uSD));
     1119        Log3Func(("[SD%RU8] Not running, skipping transfer\n", uSD));
    9801120        fProceed = false;
    9811121    }
     1122
    9821123    else if (HDA_STREAM_REG(pThis, STS, uSD) & HDA_SDSTS_BCIS)
    9831124    {
    984         Log3Func(("[SD%RU8] BCIS bit set\n", uSD));
     1125        Log3Func(("[SD%RU8] BCIS bit set, skipping transfer\n", uSD));
     1126#ifdef HDA_STRICT
     1127        /* Timing emulation bug or guest is misbehaving -- let me know. */
     1128        AssertMsgFailed(("BCIS bit for stream #%RU8 still set when it shouldn't\n", uSD));
     1129#endif
    9851130        fProceed = false;
    9861131    }
     
    10061151    pStreamShared->State.tsTransferLast = tsNow;
    10071152
    1008     /* Sanity checks. */
     1153    /* Register sanity checks. */
    10091154    Assert(uSD < HDA_MAX_STREAMS);
    10101155    Assert(pStreamShared->u64BDLBase);
     
    10141159    /* State sanity checks. */
    10151160    Assert(ASMAtomicReadBool(&pStreamShared->State.fInReset) == false);
     1161    Assert(ASMAtomicReadBool(&pStreamShared->State.fRunning));
     1162
     1163    /* Transfer sanity checks. */
     1164    Assert(pStreamShared->State.cbTransferSize);
     1165    Assert(pStreamShared->State.cbTransferChunk <= pStreamShared->State.cbTransferSize);
    10161166
    10171167    int rc = VINF_SUCCESS;
     
    10251175    }
    10261176
    1027     uint32_t cbToProcess = RT_MIN(pStreamShared->State.cbTransferSize - pStreamShared->State.cbTransferProcessed,
    1028                                   pStreamShared->State.cbTransferChunk);
    1029 
    1030     Log3Func(("[SD%RU8] cbToProcess=%RU32, cbToProcessMax=%RU32\n", uSD, cbToProcess, cbToProcessMax));
    1031 
    1032     if (cbToProcess > cbToProcessMax)
    1033     {
    1034         LogFunc(("[SD%RU8] Limiting transfer (cbToProcess=%RU32, cbToProcessMax=%RU32)\n", uSD, cbToProcess, cbToProcessMax));
    1035 
    1036         /* Never process more than a stream currently can handle. */
    1037         cbToProcess = cbToProcessMax;
    1038     }
     1177    uint32_t cbToProcess = RT_MIN(pStreamShared->State.cbTransferSize, pStreamShared->State.cbTransferChunk);
     1178
     1179    Assert(cbToProcess);                                                     /* Nothing to process when there should be data. Accounting bug? */
     1180    AssertStmt(cbToProcess <= cbToProcessMax, cbToProcess = cbToProcessMax); /* More data to process than maximum allowed. */
    10391181
    10401182    uint32_t cbProcessed = 0;
     
    10531195        if (pStreamShared->State.cfPosAdjustLeft)
    10541196            cbChunk = RT_MIN(cbChunk, uint32_t(pStreamShared->State.cfPosAdjustLeft * pStreamR3->State.Mapping.cbFrameSize));
    1055 
    1056         Log3Func(("[SD%RU8] cbChunk=%RU32, cPosAdjustFramesLeft=%RU16\n",
    1057                   uSD, cbChunk, pStreamShared->State.cfPosAdjustLeft));
    10581197
    10591198        if (!cbChunk)
     
    12611400        if (cbDMA)
    12621401        {
    1263             const size_t cbCircBufUsed = RTCircBufUsed(pCircBuf); RT_NOREF(cbCircBufUsed);
    1264 
    1265             Log3Func(("[SD%RU8] cbDMA=%RU32, cbUsed=%zu, uFIFOW=%RU8, uFIFOS=%RU8\n",
    1266                       uSD, cbDMA, cbCircBufUsed, pStreamShared->u8FIFOW, pStreamShared->u8FIFOS));
    1267 
    12681402            /* We always increment the position of DMA buffer counter because we're always reading
    12691403             * into an intermediate DMA buffer. */
     
    12811415            }
    12821416
     1417            Log3Func(("[SD%RU8] cbDMA=%RU32 -> %R[bdle]\n", uSD, cbDMA, pBDLE));
     1418        }
     1419
     1420        if (hdaR3BDLEIsComplete(pBDLE))
     1421        {
     1422            Log3Func(("[SD%RU8] Completed %R[bdle]\n", uSD, pBDLE));
     1423
     1424            /* Make sure to also update the wall clock when a BDLE is complete.
     1425             * Needed for Windows 10 guests. */
     1426            hdaR3WalClkSet(pThis, pThisCC,
     1427                             hdaWalClkGetCurrent(pThis)
     1428                           + hdaR3StreamPeriodFramesToWalClk(pPeriod,
     1429                                                               pBDLE->Desc.u32BufSize
     1430                                                             / pStreamR3->State.Mapping.cbFrameSize),
     1431                           false /* fForce */);
     1432
    12831433            /*
    12841434             * Update the stream's current position.
    12851435             * Do this as accurate and close to the actual data transfer as possible.
    12861436             * All guetsts rely on this, depending on the mechanism they use (LPIB register or DMA counters).
     1437             *
     1438             * Note for Windows 10: The OS' driver is *very* picky about *when* the (DMA) positions get updated!
     1439             *                      Not doing this at the right time will result in ugly sound crackles!
    12871440             */
    1288             uint32_t cbStreamPos = hdaR3StreamGetPosition(pThis, pStreamShared);
    1289             if (cbStreamPos == pStreamShared->u32CBL)
    1290                 cbStreamPos = 0;
    1291 
    1292             hdaR3StreamSetPosition(pStreamShared, pDevIns, pThis, cbStreamPos + cbDMA);
    1293         }
    1294 
    1295         if (hdaR3BDLEIsComplete(pBDLE))
    1296         {
    1297             Log3Func(("[SD%RU8] Complete: %R[bdle]\n", uSD, pBDLE));
     1441            hdaR3StreamSetPositionAdd(pStreamShared, pDevIns, pThis, pBDLE->Desc.u32BufSize);
    12981442
    12991443                /* Does the current BDLE require an interrupt to be sent? */
     
    13161460                              ("Too many pending interrupts (%RU8) for stream #%RU8\n",
    13171461                               pStreamShared->State.cTransferPendingInterrupts, uSD));
     1462
     1463                    /* Assert the interrupt before actually fetching the next BDLE below. */
     1464                    if (pStreamShared->State.cTransferPendingInterrupts)
     1465                    {
     1466                        Log3Func(("[SD%RU8] Scheduling interrupt (now %RU8 total)\n", uSD, pStreamShared->State.cTransferPendingInterrupts));
     1467
     1468                        /*
     1469                         * Set the stream's BCIS bit.
     1470                         *
     1471                         * Note: This only must be done if the whole period is complete, and not if only
     1472                         * one specific BDL entry is complete (if it has the IOC bit set).
     1473                         *
     1474                         * This will otherwise confuses the guest when it 1) deasserts the interrupt,
     1475                         * 2) reads SDSTS (with BCIS set) and then 3) too early reads a (wrong) WALCLK value.
     1476                         *
     1477                         * snd_hda_intel on Linux will tell.
     1478                         */
     1479                        HDA_STREAM_REG(pThis, STS, uSD) |= HDA_SDSTS_BCIS;
     1480
     1481                        /* Trigger an interrupt first and let hdaRegWriteSDSTS() deal with
     1482                         * ending / beginning a period. */
     1483                        HDA_PROCESS_INTERRUPT(pDevIns, pThis);
     1484                    }
    13181485                }
    13191486            }
     
    13381505    }
    13391506
    1340     Log3Func(("[SD%RU8] cbToProcess=%RU32, cbProcessed=%RU32, cbLeft=%RU32, %R[bdle], rc=%Rrc\n",
    1341               uSD, cbToProcess, cbProcessed, cbLeft, pBDLE, rc));
    1342 
    13431507    /* Sanity. */
    13441508    Assert(cbProcessed == cbToProcess);
     
    13511515        hdaR3StreamPeriodInc(pPeriod, RT_MIN(cbProcessed / pStreamR3->State.Mapping.cbFrameSize,
    13521516                                             hdaR3StreamPeriodGetRemainingFrames(pPeriod)));
    1353 
    1354         pStreamShared->State.cbTransferProcessed += cbProcessed;
    1355     }
    1356 
    1357     /* Make sure that we never report more stuff processed than initially announced. */
    1358     if (pStreamShared->State.cbTransferProcessed > pStreamShared->State.cbTransferSize)
    1359         pStreamShared->State.cbTransferProcessed = pStreamShared->State.cbTransferSize;
    1360 
    1361     uint32_t cbTransferLeft     = pStreamShared->State.cbTransferSize - pStreamShared->State.cbTransferProcessed;
    1362     bool     fTransferComplete  = !cbTransferLeft;
    1363     uint64_t tsTransferNext     = 0;
     1517    }
     1518
     1519    const bool fTransferComplete  = cbLeft == 0;
     1520    uint64_t   tsTransferNext     = 0;
    13641521
    13651522    if (fTransferComplete)
     
    13801537                                                 hdaWalClkGetCurrent(pThis)
    13811538                                               + hdaR3StreamPeriodFramesToWalClk(pPeriod,
    1382                                                                                    pStreamShared->State.cbTransferProcessed
     1539                                                                                   cbProcessed
    13831540                                                                                 / pStreamR3->State.Mapping.cbFrameSize),
    13841541                                               false /* fForce */);
     
    13871544
    13881545    /* Does the period have any interrupts outstanding? */
    1389     if (pStreamShared->State.cTransferPendingInterrupts)
    1390     {
    1391         Log3Func(("[SD%RU8] Scheduling interrupt\n", uSD));
    1392 
    1393         /*
    1394          * Set the stream's BCIS bit.
    1395          *
    1396          * Note: This only must be done if the whole period is complete, and not if only
    1397          * one specific BDL entry is complete (if it has the IOC bit set).
    1398          *
    1399          * This will otherwise confuses the guest when it 1) deasserts the interrupt,
    1400          * 2) reads SDSTS (with BCIS set) and then 3) too early reads a (wrong) WALCLK value.
    1401          *
    1402          * snd_hda_intel on Linux will tell.
    1403          */
    1404         HDA_STREAM_REG(pThis, STS, uSD) |= HDA_SDSTS_BCIS;
    1405 
    1406         /* Trigger an interrupt first and let hdaRegWriteSDSTS() deal with
    1407          * ending / beginning a period. */
    1408         HDA_PROCESS_INTERRUPT(pDevIns, pThis);
    1409     }
    1410     else /* Transfer still in-flight -- schedule the next timing slot. */
    1411     {
    1412         uint32_t cbTransferNext = cbTransferLeft;
    1413 
    1414         /* No data left to transfer anymore or do we have more data left
    1415          * than we can transfer per timing slot? Clamp. */
    1416         if (   !cbTransferNext
    1417             || cbTransferNext > pStreamShared->State.cbTransferChunk)
    1418         {
    1419             cbTransferNext = pStreamShared->State.cbTransferChunk;
    1420         }
    1421 
    1422         tsTransferNext = tsNow + (cbTransferNext * pStreamShared->State.cTicksPerByte);
    1423 
    1424         /*
    1425          * If the current transfer is complete, reset our counter.
    1426          *
    1427          * This can happen for examlpe if the guest OS (like macOS) sets up
    1428          * big BDLEs without IOC bits set (but for the last one) and the
    1429          * transfer is complete before we reach such a BDL entry.
    1430          */
    1431         if (fTransferComplete)
    1432             pStreamShared->State.cbTransferProcessed = 0;
     1546    if (!pStreamShared->State.cTransferPendingInterrupts)
     1547    {
     1548        /* No, set relative timer ticks for the next transfer to happen.
     1549         * This must happen at a constant rate. */
     1550        tsTransferNext = pStreamShared->State.cTransferTicks;
    14331551    }
    14341552
     
    14361554    if (tsTransferNext) /* Can be 0 if no next transfer is needed. */
    14371555    {
    1438         Log3Func(("[SD%RU8] Scheduling timer\n", uSD));
    1439 
    1440         LogFunc(("Timer set SD%RU8\n", uSD));
     1556        Log3Func(("[SD%RU8] Scheduling timer @ %RU64\n", uSD, tsNow + tsTransferNext));
     1557
    14411558        Assert(!fInTimer || tsNow == PDMDevHlpTimerGet(pDevIns, pStreamShared->hTimer));
    14421559        hdaR3TimerSet(pDevIns, pStreamShared, tsTransferNext,
     
    14481565    pStreamShared->State.tsTransferLast = tsNow;
    14491566
    1450     Log3Func(("[SD%RU8] cbTransferLeft=%RU32 -- %RU32/%RU32\n",
    1451               uSD, cbTransferLeft, pStreamShared->State.cbTransferProcessed, pStreamShared->State.cbTransferSize));
     1567    Log3Func(("[SD%RU8] %R[bdle] -- %RU32/%RU32\n",
     1568              uSD, pBDLE, cbProcessed, pStreamShared->State.cbTransferSize));
    14521569    Log3Func(("[SD%RU8] fTransferComplete=%RTbool, cTransferPendingInterrupts=%RU8\n",
    14531570              uSD, fTransferComplete, pStreamShared->State.cTransferPendingInterrupts));
    14541571    Log3Func(("[SD%RU8] tsNow=%RU64, tsTransferNext=%RU64 (in %RU64 ticks)\n",
    1455               uSD, tsNow, tsTransferNext, tsTransferNext - tsNow));
     1572              uSD, tsNow, tsTransferNext, tsTransferNext ? tsTransferNext - tsNow : 0));
     1573
     1574    LogFlowFuncLeave();
    14561575
    14571576    hdaR3StreamPeriodUnlock(pPeriod);
     
    15091628# endif
    15101629        {
    1511             const uint32_t cbStreamFree = hdaR3StreamGetFree(pStreamR3);
    1512             if (cbStreamFree)
    1513             {
    1514                 /* Do the DMA transfer. */
    1515                 rc2 = hdaR3StreamTransfer(pDevIns, pThis, pThisCC, pStreamShared, pStreamR3, cbStreamFree, fInTimer);
    1516                 AssertRC(rc2);
    1517             }
     1630
     1631            uint32_t cbStreamFree = hdaR3StreamGetFree(pStreamR3);
     1632            if (!cbStreamFree)
     1633            {
     1634                LogRel2(("HDA: Warning: Hit stream #%RU8 overflow, dropping audio data\n", pStreamShared->u8SD));
     1635# ifdef HDA_STRICT
     1636                AssertMsgFailed(("Hit stream #%RU8 overflow -- timing bug?\n", pStreamShared->u8SD));
     1637# endif
     1638                /* When hitting an overflow, drop all remaining data to make space for current data.
     1639                 * This is needed in order to keep the device emulation running at a constant rate,
     1640                 * at the cost of losing old data. */
     1641                RTCircBufReset(pStreamR3->State.pCircBuf);
     1642                cbStreamFree = hdaR3StreamGetFree(pStreamR3);
     1643            }
     1644
     1645            /* Do the DMA transfer. */
     1646            rc2 = hdaR3StreamTransfer(pDevIns, pThis, pThisCC, pStreamShared, pStreamR3, cbStreamFree, fInTimer);
     1647            AssertRC(rc2);
     1648
     1649            const uint64_t tsNowNs = RTTimeNanoTS();
     1650
     1651            /* Never updated yet? Set initial timestamp. */
     1652            if (pStreamShared->State.tsLastUpdateNs == 0)
     1653                pStreamShared->State.tsLastUpdateNs = tsNowNs;
    15181654
    15191655            /* Only read from the HDA stream at the given scheduling rate. */
    1520             const uint64_t tsNowNs = RTTimeNanoTS();
    15211656            if (tsNowNs - pStreamShared->State.tsLastUpdateNs >= pStreamShared->State.Cfg.Device.cMsSchedulingHint * RT_NS_1MS)
    15221657            {
     
    15241659                pStreamShared->State.tsLastUpdateNs = tsNowNs;
    15251660            }
     1661
     1662# ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
    15261663        }
    1527 
    1528         Log3Func(("[SD%RU8] fInTimer=%RTbool, fDoRead=%RTbool\n", pStreamShared->u8SD, fInTimer, fDoRead));
     1664# endif
     1665        Log3Func(("[SD%RU8] fInTimer=%RTbool, tsLastUpdateNs=%RU64, fDoRead=%RTbool\n",
     1666                  pStreamShared->u8SD, fInTimer, pStreamShared->State.tsLastUpdateNs, fDoRead));
    15291667
    15301668# ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
  • trunk/src/VBox/Devices/Audio/HDAStream.h

    r87319 r87567  
    136136    /** Transfer chunk size (in bytes) of a transfer period. */
    137137    uint32_t                cbTransferChunk;
    138     /** How many bytes already have been processed in within
    139      *  the current transfer period. */
    140     uint32_t                cbTransferProcessed;
    141138    /** How many interrupts are pending due to
    142139     *  BDLE interrupt-on-completion (IOC) bits set. */
    143140    uint8_t                 cTransferPendingInterrupts;
    144     uint8_t                 abPadding2[3];
     141    uint8_t                 abPadding2[7];
    145142    /** The stream's timer Hz rate.
    146143     *  This value can can be different from the device's default Hz rate,
     
    280277                                     PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3, uint8_t uSD);
    281278int                 hdaR3StreamEnable(PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3, bool fEnable);
    282 /* uint32_t            hdaR3StreamGetPosition(PHDASTATE pThis, PHDASTREAMR3 pStreamShared); - only used in HDAStream.cpp */
    283 /*void                hdaR3StreamSetPosition(PHDASTREAM pStream, PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t u32LPIB); - only used in HDAStream.cpp */
    284 /*uint32_t            hdaR3StreamGetFree(PHDASTREAM pStream); - only used in HDAStream.cpp */
    285 /*uint32_t            hdaR3StreamGetUsed(PHDASTREAM pStream); - only used in HDAStream.cpp */
     279void                hdaR3StreamSetPositionAdd(PHDASTREAM pStreamShared, PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t uToAdd);
    286280bool                hdaR3StreamTransferIsScheduled(PHDASTREAM pStreamShared, uint64_t tsNow);
    287281uint64_t            hdaR3StreamTransferGetNext(PHDASTREAM pStreamShared);
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