VirtualBox

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


Ignore:
Timestamp:
Mar 18, 2021 1:38:31 AM (4 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
143321
Message:

DevHDA: Rewrote the wall clock code to base it on the virtual sync clock with a start offset and holding it back according to DMA progress. Introduced new saved state version. bugref:9890

Location:
trunk/src/VBox/Devices/Audio
Files:
2 deleted
7 edited

Legend:

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

    r88168 r88170  
    5959#include "HDAStream.h"
    6060#include "HDAStreamMap.h"
    61 #include "HDAStreamPeriod.h"
    6261
    6362#include "DrvAudio.h"
     
    534533};
    535534
    536 /** HDASTREAMPERIOD field descriptors for the v7 saved state. */
    537 static SSMFIELD const g_aSSMStreamPeriodFields7[] =
    538 {
    539     SSMFIELD_ENTRY(HDASTREAMPERIOD, u64StartWalClk),
    540     SSMFIELD_ENTRY(HDASTREAMPERIOD, u64ElapsedWalClk),
    541     SSMFIELD_ENTRY(HDASTREAMPERIOD, cFramesTransferred),
    542     SSMFIELD_ENTRY_OLD(cIntPending, sizeof(uint8_t)),   /** @todo Not sure what we should for non-zero values on restore... ignoring it for now.  */
    543     SSMFIELD_ENTRY_TERM()
    544 };
    545 
    546535/** HDABDLE field descriptors for the v1 thru v4 saved states. */
    547536static SSMFIELD const g_aSSMStreamBdleFields1234[] =
     
    11541143}
    11551144
     1145/**
     1146 * Gets the wall clock.
     1147 *
     1148 * Used by hdaRegReadWALCLK() and 'info hda'.
     1149 *
     1150 * @returns The full wall clock value
     1151 * @param   pDevIns     The device instance.
     1152 * @param   pThis       The shared HDA device state.
     1153 */
     1154static uint64_t hdaGetWallClock(PPDMDEVINS pDevIns, PHDASTATE pThis)
     1155{
     1156    /*
     1157     * The wall clock is calculated from the virtual sync clock.  Since
     1158     * the clock is supposed to reset to zero on controller reset, a
     1159     * start offset is subtracted.
     1160     *
     1161     * In addition, we hold the clock back when there are active DMA engines
     1162     * so that the guest won't conclude we've gotten further in the buffer
     1163     * processing than what we really have. (We generally read a whole buffer
     1164     * at once when the IOC is due, so we're a lot later than what real
     1165     * hardware would be in reading/writing the buffers.)
     1166     *
     1167     * Here are some old notes from the DMA engine that might be useful even
     1168     * if a little dated:
     1169     *
     1170     * Note 1) Only certain guests (like Linux' snd_hda_intel) rely on the WALCLK register
     1171     *         in order to determine the correct timing of the sound device. Other guests
     1172     *         like Windows 7 + 10 (or even more exotic ones like Haiku) will completely
     1173     *         ignore this.
     1174     *
     1175     * Note 2) When updating the WALCLK register too often / early (or even in a non-monotonic
     1176     *         fashion) this *will* upset guest device drivers and will completely fuck up the
     1177     *         sound output. Running VLC on the guest will tell!
     1178     */
     1179    uint64_t const uFreq    = PDMDevHlpTimerGetFreq(pDevIns, pThis->aStreams[0].hTimer);
     1180    Assert(uFreq <= UINT32_MAX);
     1181    uint64_t const tsStart  = 0; /** @todo pThis->tsWallClkStart (as it is reset on controller reset) */
     1182    uint64_t const tsNow    = PDMDevHlpTimerGet(pDevIns, pThis->aStreams[0].hTimer);
     1183
     1184    /* Find the oldest DMA transfer timestamp from the active streams. */
     1185    int            iDmaNow  = -1;
     1186    uint64_t       tsDmaNow = tsNow;
     1187    for (size_t i = 0; i < RT_ELEMENTS(pThis->aStreams); i++)
     1188        if (   pThis->aStreams[i].State.fRunning
     1189            && pThis->aStreams[i].State.tsTransferLast < tsDmaNow
     1190            && pThis->aStreams[i].State.tsTransferLast > tsStart)
     1191        {
     1192            tsDmaNow = pThis->aStreams[i].State.tsTransferLast;
     1193            iDmaNow  = (int)i;
     1194        }
     1195
     1196    /* Convert it to wall clock ticks. */
     1197    uint64_t const uWallClkNow = ASMMultU64ByU32DivByU32(tsDmaNow - tsStart,
     1198                                                         24000000 /*Wall clock frequency */,
     1199                                                         uFreq);
     1200    Log3Func(("Returning %#RX64 - tsNow=%#RX64 tsDmaNow=%#RX64 (%d) -> %#RX64\n",
     1201              uWallClkNow, tsNow, tsDmaNow, iDmaNow, tsNow - tsDmaNow));
     1202    RT_NOREF(iDmaNow);
     1203    return uWallClkNow;
     1204}
     1205
    11561206static VBOXSTRICTRC hdaRegReadWALCLK(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value)
    11571207{
    11581208    RT_NOREF(pDevIns, iReg);
    1159 
    1160     const uint64_t u64WalClkCur = ASMAtomicReadU64(&pThis->u64WalClk);
    1161     *pu32Value = RT_LO_U32(u64WalClkCur);
    1162 
     1209    *pu32Value = (uint32_t)hdaGetWallClock(pDevIns, pThis);
    11631210    return VINF_SUCCESS;
    11641211}
     
    14311478                    pThisCC->cStreamsActive++;
    14321479
    1433                     /* (Re-)init the stream's period. */
    1434                     hdaR3StreamPeriodInit(&pStreamShared->State.Period, uSD, pStreamShared->u16LVI,
    1435                                           pStreamShared->u32CBL, &pStreamShared->State.Cfg);
    1436 
    1437                     /* Begin a new period for this stream. */
    1438                     rc2 = hdaR3StreamPeriodBegin(&pStreamShared->State.Period,
    1439                                                  hdaWalClkGetCurrent(pThis) /* Use current wall clock time */);
    1440                     AssertRC(rc2);
    1441 
    14421480                    /** @todo move this into a HDAStream.cpp function. */
    14431481                    uint64_t tsNow;
     
    14521490                        /* Input streams: Arm the timer and kick the AIO thread. */
    14531491                        tsNow = PDMDevHlpTimerGet(pDevIns, pStreamShared->hTimer);
     1492                        pStreamShared->State.tsTransferLast = tsNow; /* for WALCLK */
     1493
    14541494                        uint64_t tsTransferNext = tsNow + pStreamShared->State.aSchedule[0].cPeriodTicks;
    14551495                        pStreamShared->State.tsTransferNext = tsTransferNext; /* legacy */
     
    14571497                        Log3Func(("[SD%RU8] tsTransferNext=%RU64 (in %RU64)\n",
    14581498                                  pStreamShared->u8SD, tsTransferNext, tsTransferNext - tsNow));
     1499
    14591500                        int rc = PDMDevHlpTimerSet(pDevIns, pStreamShared->hTimer, tsTransferNext);
    14601501                        AssertRC(rc);
     
    14711512                    if (pThisCC->cStreamsActive)
    14721513                        pThisCC->cStreamsActive--;
    1473 
    1474                     /* Reset the period. */
    1475                     hdaR3StreamPeriodReset(&pStreamShared->State.Period);
    14761514
    14771515                    hdaR3StreamMarkStopped(pStreamShared);
     
    29182956    HDA_REG(pThis, STATESTS) = 0x1;
    29192957
     2958    /* Reset the wall clock. */
     2959    pThis->tsWalClkStart = PDMDevHlpTimerGet(pDevIns, pThis->aStreams[0].hTimer);
     2960
    29202961    LogFlowFuncLeave();
    29212962    LogRel(("HDA: Reset\n"));
     
    34023443    AssertRCReturn(rc, rc);
    34033444
    3404     rc = pHlp->pfnSSMPutStructEx(pSSM, &pStreamShared->State.Period, sizeof(pStreamShared->State.Period),
    3405                                  0 /* fFlags */, g_aSSMStreamPeriodFields7, NULL);
    3406     AssertRCReturn(rc, rc);
    3407 
    34083445    uint32_t cbCircBufSize = 0;
    34093446    uint32_t cbCircBufUsed = 0;
     
    34753512
    34763513    /* Save controller-specifc internals. */
    3477     pHlp->pfnSSMPutU64(pSSM, pThis->u64WalClk);
     3514    pHlp->pfnSSMPutU64(pSSM, pThis->tsWalClkStart);
    34783515    pHlp->pfnSSMPutU8(pSSM, pThis->u8IRQL);
    34793516
     
    35263563            hdaR3StreamAsyncIOEnable(pStreamR3, true /* fEnable */);
    35273564#endif
    3528             /* Resume the stream's period. */
    3529             hdaR3StreamPeriodResume(&pStreamShared->State.Period);
    3530 
    35313565            /* (Re-)enable the stream. */
    35323566            rc2 = hdaR3StreamEnable(pStreamShared, pStreamR3, true /* fEnable */);
     
    39103944        || pHlp->pfnSSMHandleVersion(pSSM)  >= VBOX_FULL_VERSION_MAKE(5, 2, 0))
    39113945    {
    3912         pHlp->pfnSSMGetU64(pSSM, &pThis->u64WalClk);
     3946        pHlp->pfnSSMGetU64(pSSM, &pThis->tsWalClkStart); /* Was current wall clock */
    39133947        rc = pHlp->pfnSSMGetU8(pSSM, &pThis->u8IRQL);
    39143948        AssertRCReturn(rc, rc);
     3949
     3950        /* Convert the saved wall clock timestamp to a start timestamp. */
     3951        if (uVersion < HDA_SAVED_STATE_WITHOUT_PERIOD && pThis->tsWalClkStart != 0)
     3952        {
     3953            uint64_t const cTimerTicksPerSec = PDMDevHlpTimerGetFreq(pDevIns, pThis->aStreams[0].hTimer);
     3954            AssertLogRel(cTimerTicksPerSec <= UINT32_MAX);
     3955            pThis->tsWalClkStart = ASMMultU64ByU32DivByU32(pThis->tsWalClkStart,
     3956                                                           cTimerTicksPerSec,
     3957                                                           24000000 /* wall clock freq */);
     3958            pThis->tsWalClkStart = PDMDevHlpTimerGet(pDevIns, pThis->aStreams[0].hTimer) - pThis->tsWalClkStart;
     3959        }
    39153960    }
    39163961
     
    39754020         * Load period state.
    39764021         */
    3977         hdaR3StreamPeriodInit(&pStreamShared->State.Period, pStreamShared->u8SD, pStreamShared->u16LVI,
    3978                               pStreamShared->u32CBL, &pStreamShared->State.Cfg);
    3979 
    3980         rc = pHlp->pfnSSMGetStructEx(pSSM, &pStreamShared->State.Period, sizeof(pStreamShared->State.Period),
    3981                                      0 /* fFlags */, g_aSSMStreamPeriodFields7, NULL);
    3982         AssertRCReturn(rc, rc);
     4022        if (uVersion <= HDA_SAVED_STATE_WITHOUT_PERIOD)
     4023        {
     4024            static SSMFIELD const s_aSSMStreamPeriodFields7[] = /* For the removed HDASTREAMPERIOD structure. */
     4025            {
     4026                SSMFIELD_ENTRY_OLD(u64StartWalClk,     sizeof(uint64_t)),
     4027                SSMFIELD_ENTRY_OLD(u64ElapsedWalClk,   sizeof(uint64_t)),
     4028                SSMFIELD_ENTRY_OLD(cFramesTransferred, sizeof(uint32_t)),
     4029                SSMFIELD_ENTRY_OLD(cIntPending, sizeof(uint8_t)),   /** @todo Not sure what we should for non-zero values on restore... ignoring it for now.  */
     4030                SSMFIELD_ENTRY_TERM()
     4031            };
     4032            uint8_t bWhatever = 0;
     4033            rc = pHlp->pfnSSMGetStructEx(pSSM, &bWhatever, sizeof(bWhatever), 0 /* fFlags */, s_aSSMStreamPeriodFields7, NULL);
     4034            AssertRCReturn(rc, rc);
     4035        }
    39834036
    39844037        /*
     
    41374190
    41384191/** Worker for hdaR3DbgInfo.  */
    4139 static void hdaR3DbgPrintRegister(PHDASTATE pThis, PCDBGFINFOHLP pHlp, int iHdaIndex)
     4192static void hdaR3DbgPrintRegister(PPDMDEVINS pDevIns, PHDASTATE pThis, PCDBGFINFOHLP pHlp, int iHdaIndex)
    41404193{
    41414194    /** @todo HDA_REG_IDX_NOMEM & GCAP both uses mem_idx zero, no flag or anything to tell them appart. */
     
    41434196        pHlp->pfnPrintf(pHlp, "%s: 0x%x\n", g_aHdaRegMap[iHdaIndex].abbrev, pThis->au32Regs[g_aHdaRegMap[iHdaIndex].mem_idx]);
    41444197    else
    4145         pHlp->pfnPrintf(pHlp, "%s: 0x%RX64\n", g_aHdaRegMap[iHdaIndex].abbrev, pThis->u64WalClk);
     4198        pHlp->pfnPrintf(pHlp, "%s: 0x%RX64\n", g_aHdaRegMap[iHdaIndex].abbrev, hdaGetWallClock(pDevIns, pThis));
    41464199}
    41474200
     
    41544207    int idxReg = hdaR3DbgLookupRegByName(pszArgs);
    41554208    if (idxReg != -1)
    4156         hdaR3DbgPrintRegister(pThis, pHlp, idxReg);
     4209        hdaR3DbgPrintRegister(pDevIns, pThis, pHlp, idxReg);
    41574210    else
    41584211        for (idxReg = 0; idxReg < HDA_NUM_REGS; ++idxReg)
    4159             hdaR3DbgPrintRegister(pThis, pHlp, idxReg);
     4212            hdaR3DbgPrintRegister(pDevIns, pThis, pHlp, idxReg);
    41604213}
    41614214
     
    50315084    for (size_t i = 0; i < HDA_MAX_STREAMS; i++)
    50325085    {
     5086        /* We need the first timer in ring-0 to calculate the wall clock (WALCLK) time. */
    50335087        rc = PDMDevHlpTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, hdaR3Timer, (void *)(uintptr_t)i,
    5034                                   TMTIMER_FLAGS_NO_CRIT_SECT | TMTIMER_FLAGS_NO_RING0,
     5088                                  TMTIMER_FLAGS_NO_CRIT_SECT | (i == 0 ? TMTIMER_FLAGS_RING0 : TMTIMER_FLAGS_NO_RING0),
    50355089                                  s_apszNames[i], &pThis->aStreams[i].hTimer);
    50365090        AssertRCReturn(rc, rc);
  • trunk/src/VBox/Devices/Audio/DevHDA.h

    r88164 r88170  
    3131#include "HDAStream.h"
    3232#include "HDAStreamMap.h"
    33 #include "HDAStreamPeriod.h"
    3433
    3534#ifdef DEBUG_andy
     
    119118    /** Current IRQ level. */
    120119    uint8_t                 u8IRQL;
    121 #ifdef VBOX_STRICT
    122     /** Wall clock (WALCLK) stale count.
    123      *  This indicates the number of set wall clock values which did not actually
    124      *  move the counter forward (stale). */
    125     uint8_t                 u8WalClkStaleCnt;
    126 #else
    127     uint8_t                 bPadding1;
    128 #endif
    129     uint8_t                 bPadding2;
    130120    /** The device timer Hz rate. Defaults to HDA_TIMER_HZ_DEFAULT. */
    131121    uint16_t                uTimerHz;
     
    139129     *  The actual buffer size in bytes will depend on the actual stream configuration. */
    140130    uint16_t                cbCircBufOutMs;
    141     uint16_t                au16Padding3[3];
    142     /** Last updated wall clock (WALCLK) counter. */
    143     uint64_t                u64WalClk;
     131    /** The start time of the wall clock (WALCLK), measured on the virtual sync clock. */
     132    uint64_t                tsWalClkStart;
    144133    /** The CORB buffer. */
    145134    uint32_t                au32CorbBuf[HDA_CORB_SIZE];
  • trunk/src/VBox/Devices/Audio/DevHDACommon.cpp

    r88137 r88170  
    104104}
    105105
    106 /**
    107  * Retrieves the currently set value for the wall clock.
    108  *
    109  * @return  IPRT status code.
    110  * @return  Currently set wall clock value.
    111  * @param   pThis               The shared HDA device state.
    112  *
    113  * @remark  Operation is atomic.
    114  */
    115 uint64_t hdaWalClkGetCurrent(PHDASTATE pThis)
    116 {
    117     return ASMAtomicReadU64(&pThis->u64WalClk);
    118 }
    119 
    120106#ifdef IN_RING3
    121 
    122 /**
    123  * Helper for hdaR3WalClkSet.
    124  */
    125 DECLINLINE(PHDASTREAMPERIOD) hdaR3SinkToStreamPeriod(PHDAMIXERSINK pSink)
    126 {
    127     PHDASTREAM pStream = hdaR3GetSharedStreamFromSink(pSink);
    128     if (pStream)
    129         return &pStream->State.Period;
    130     return NULL;
    131 }
    132 
    133 /**
    134  * Returns the current maximum value the wall clock counter can be set to.
    135  *
    136  * This maximum value depends on all currently handled HDA streams and their own current timing.
    137  *
    138  * @return  Current maximum value the wall clock counter can be set to.
    139  * @param   pThis               The shared HDA device state.
    140  * @param   pThisCC             The ring-3 HDA device state.
    141  *
    142  * @remark  Does not actually set the wall clock counter.
    143  *
    144  */
    145 uint64_t hdaR3WalClkGetMax(PHDASTATE pThis, PHDASTATER3 pThisCC)
    146 {
    147     const uint64_t u64WalClkCur       = ASMAtomicReadU64(&pThis->u64WalClk);
    148     const uint64_t u64FrontAbsWalClk  = pThisCC->SinkFront.pStreamShared
    149                                       ? hdaR3StreamPeriodGetAbsElapsedWalClk(&pThisCC->SinkFront.pStreamShared->State.Period)  : 0;
    150 # ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
    151 #  error "Implement me!"
    152 # endif
    153     const uint64_t u64LineInAbsWalClk = pThisCC->SinkLineIn.pStreamShared
    154                                       ? hdaR3StreamPeriodGetAbsElapsedWalClk(&pThisCC->SinkLineIn.pStreamShared->State.Period) : 0;
    155 # ifdef VBOX_WITH_HDA_MIC_IN
    156     const uint64_t u64MicInAbsWalClk  = pThisCC->SinkMicIn.pStreamShared
    157                                       ? hdaR3StreamPeriodGetAbsElapsedWalClk(&pThisCC->SinkMicIn.pStreamShared->State.Period)  : 0;
    158 # endif
    159 
    160     uint64_t u64WalClkNew = RT_MAX(u64WalClkCur, u64FrontAbsWalClk);
    161 # ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
    162 #  error "Implement me!"
    163 # endif
    164     u64WalClkNew          = RT_MAX(u64WalClkNew, u64LineInAbsWalClk);
    165 # ifdef VBOX_WITH_HDA_MIC_IN
    166     u64WalClkNew          = RT_MAX(u64WalClkNew, u64MicInAbsWalClk);
    167 # endif
    168 
    169     Log3Func(("%RU64 -> Front=%RU64, LineIn=%RU64 -> %RU64\n",
    170               u64WalClkCur, u64FrontAbsWalClk, u64LineInAbsWalClk, u64WalClkNew));
    171 
    172     return u64WalClkNew;
    173 }
    174 
    175 /**
    176  * Sets the actual WALCLK register to the specified wall clock value.
    177  * The specified wall clock value only will be set (unless fForce is set to true) if all
    178  * handled HDA streams have passed (in time) that value. This guarantees that the WALCLK
    179  * register stays in sync with all handled HDA streams.
    180  *
    181  * @return  true if the WALCLK register has been updated, false if not.
    182  * @param   pThis               The shared HDA device state.
    183  * @param   pThisCC             The ring-3 HDA device state.
    184  * @param   u64WalClk           Wall clock value to set WALCLK register to.
    185  * @param   fForce              Whether to force setting the wall clock value or not.
    186  */
    187 bool hdaR3WalClkSet(PHDASTATE pThis, PHDASTATER3 pThisCC, uint64_t u64WalClk, bool fForce)
    188 {
    189     const bool     fFrontPassed       = hdaR3StreamPeriodHasPassedAbsWalClk( hdaR3SinkToStreamPeriod(&pThisCC->SinkFront), u64WalClk);
    190     const uint64_t u64FrontAbsWalClk  = hdaR3StreamPeriodGetAbsElapsedWalClk(hdaR3SinkToStreamPeriod(&pThisCC->SinkFront));
    191 # ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
    192 #  error "Implement me!"
    193 # endif
    194 
    195     const bool     fLineInPassed      = hdaR3StreamPeriodHasPassedAbsWalClk (hdaR3SinkToStreamPeriod(&pThisCC->SinkLineIn), u64WalClk);
    196     const uint64_t u64LineInAbsWalClk = hdaR3StreamPeriodGetAbsElapsedWalClk(hdaR3SinkToStreamPeriod(&pThisCC->SinkLineIn));
    197 # ifdef VBOX_WITH_HDA_MIC_IN
    198     const bool     fMicInPassed       = hdaR3StreamPeriodHasPassedAbsWalClk (hdaR3SinkToStreamPeriod(&pThisCC->SinkMicIn),  u64WalClk);
    199     const uint64_t u64MicInAbsWalClk  = hdaR3StreamPeriodGetAbsElapsedWalClk(hdaR3SinkToStreamPeriod(&pThisCC->SinkMicIn));
    200 # endif
    201 
    202 # ifdef VBOX_STRICT
    203     const uint64_t u64WalClkCur       = ASMAtomicReadU64(&pThis->u64WalClk);
    204 # endif
    205 
    206     /* Only drive the WALCLK register forward if all (active) stream periods have passed
    207      * the specified point in time given by u64WalClk. */
    208     if (  (   fFrontPassed
    209 # ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
    210 #  error "Implement me!"
    211 # endif
    212            && fLineInPassed
    213 # ifdef VBOX_WITH_HDA_MIC_IN
    214            && fMicInPassed
    215 # endif
    216           )
    217        || fForce)
    218     {
    219         if (!fForce)
    220         {
    221             /* Get the maximum value of all periods we need to handle.
    222              * Not the most elegant solution, but works for now ... */
    223             u64WalClk = RT_MAX(u64WalClk, u64FrontAbsWalClk);
    224 # ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
    225 #  error "Implement me!"
    226 # endif
    227             u64WalClk = RT_MAX(u64WalClk, u64LineInAbsWalClk);
    228 # ifdef VBOX_WITH_HDA_MIC_IN
    229             u64WalClk = RT_MAX(u64WalClk, u64MicInAbsWalClk);
    230 # endif
    231 
    232 # ifdef VBOX_STRICT
    233             AssertMsg(u64WalClk >= u64WalClkCur,
    234                       ("Setting WALCLK to a value going backwards does not make any sense (old %RU64 vs. new %RU64)\n",
    235                        u64WalClkCur, u64WalClk));
    236             if (u64WalClk == u64WalClkCur)     /* Setting a stale value? */
    237             {
    238                 if (pThis->u8WalClkStaleCnt++ > 3)
    239                     AssertMsgFailed(("Setting WALCLK to a stale value (%RU64) too often isn't a good idea really. "
    240                                      "Good luck with stuck audio stuff.\n", u64WalClk));
    241             }
    242             else
    243                 pThis->u8WalClkStaleCnt = 0;
    244 # endif
    245         }
    246 
    247         /* Set the new WALCLK value. */
    248         ASMAtomicWriteU64(&pThis->u64WalClk, u64WalClk);
    249     }
    250 
    251     const uint64_t u64WalClkNew = hdaWalClkGetCurrent(pThis);
    252 
    253     Log3Func(("Cur: %RU64, New: %RU64 (force %RTbool) -> %RU64 %s\n",
    254               u64WalClkCur, u64WalClk, fForce,
    255               u64WalClkNew, u64WalClkNew == u64WalClk ? "[OK]" : "[DELAYED]"));
    256 
    257     return (u64WalClkNew == u64WalClk);
    258 }
    259 
    260107/**
    261108 * Returns the default (mixer) sink from a given SD#.
     
    299146    return NULL;
    300147}
    301 
    302148#endif /* IN_RING3 */
    303149
  • trunk/src/VBox/Devices/Audio/DevHDACommon.h

    r88164 r88170  
    595595/** @} */
    596596
    597 /** @name Wall clock (WALCLK) functions.
    598  * @{
    599  */
    600 uint64_t      hdaWalClkGetCurrent(PHDASTATE pThis);
    601 #ifdef IN_RING3
    602 uint64_t      hdaR3WalClkGetMax(PHDASTATE pThis, PHDASTATER3 pThisCC);
    603 bool          hdaR3WalClkSet(PHDASTATE pThis, PHDASTATER3 pThisCC, uint64_t u64WalClk, bool fForce);
    604 #endif
    605 /** @} */
    606 
    607597/** @name Register functions.
    608598 * @{
  • trunk/src/VBox/Devices/Audio/HDACodec.h

    r87799 r88170  
    985985/** @name DevHDA saved state versions
    986986 * @{ */
     987/** The current staved state version. */
     988#define HDA_SAVED_STATE_VERSION  HDA_SAVED_STATE_WITHOUT_PERIOD
     989
     990/** Removed period and redefined wall clock. */
     991#define HDA_SAVED_STATE_WITHOUT_PERIOD 8
    987992/** Added (Controller):              Current wall clock value (this independent from WALCLK register value).
    988993  * Added (Controller):              Current IRQ level.
     
    992997  * Added (Current BDLE per stream): Struct g_aSSMBDLEDescFields7.
    993998  * Added (Current BDLE per stream): Struct g_aSSMBDLEStateFields7. */
    994 #define HDA_SAVED_STATE_VERSION  7
     999#define HDA_SAVED_STATE_VERSION_7 7
    9951000/** Saves the current BDLE state.
    9961001 * @since 5.0.14 (r104839) */
  • trunk/src/VBox/Devices/Audio/HDAStream.cpp

    r88166 r88170  
    8787#endif
    8888
    89     rc = hdaR3StreamPeriodCreate(&pStreamShared->State.Period);
    90     AssertRCReturn(rc, rc);
    91 
    9289#ifdef DEBUG
    9390    rc = RTCritSectInit(&pStreamR3->Dbg.CritSect);
     
    195192        pStreamR3->State.pCircBuf = NULL;
    196193    }
    197 
    198     hdaR3StreamPeriodDestroy(&pStreamShared->State.Period);
    199194
    200195#ifdef DEBUG
     
    852847    pStreamR3->State.offRead  = 0;
    853848
    854     /* Reset the stream's period. */
    855     hdaR3StreamPeriodReset(&pStreamShared->State.Period);
    856 
    857849#ifdef DEBUG
    858850    pStreamR3->Dbg.cReadsTotal      = 0;
     
    936928    if (RT_SUCCESS(rc))
    937929    {
     930        if (fEnable)
     931            pStreamShared->State.tsTransferLast = 0; /* Make sure it's not stale and messes up WALCLK calculations. */
    938932        pStreamShared->State.fRunning = fEnable;
    939933    }
     
    10541048        return (uint32_t)RTCircBufFree(pStreamR3->State.pCircBuf);
    10551049    return 0;
     1050}
     1051
     1052/**
     1053 * Converts frame count to wall clock ticks (WALCLK).
     1054 *
     1055 * @returns Wall clock ticks.
     1056 * @param   pStream     The stream to do the conversion for.
     1057 * @param   cFrames     Number of audio frames.
     1058 */
     1059DECLINLINE(uint64_t) hdaR3StreamFramesToWalClk(PHDASTREAM pStreamShared, uint32_t cFrames)
     1060{
     1061    const uint32_t uHz = RT_MAX(pStreamShared->State.Cfg.Props.uHz, 1 /* prevent div/0 */);
     1062    return ASMMultU32ByU32DivByU32(cFrames, 24000000 /* 24 MHz wall clock (WALCLK). */ , uHz);
    10561063}
    10571064
     
    11511158 * @param   pszFunction     The function name (for logging).
    11521159 */
    1153 DECLINLINE(bool) hdaR3StreamDoDmaPrologue(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTREAM pStreamShared, uint8_t uSD,
     1160DECLINLINE(bool) hdaR3StreamDoDmaPrologue(PHDASTATE pThis, PHDASTREAM pStreamShared, uint8_t uSD,
    11541161                                          uint64_t tsNowNs, const char *pszFunction)
    11551162{
     
    11991206    Log3(("%s: [SD%RU8] tsDeltaNs=%'RU64 ns\n", pszFunction, uSD, tsNowNs - pStreamShared->State.tsLastTransferNs));
    12001207    pStreamShared->State.tsLastTransferNs = tsNowNs;
    1201     pStreamShared->State.tsTransferLast   = PDMDevHlpTimerGet(pDevIns, pStreamShared->hTimer);
    12021208
    12031209    /*
     
    12171223 * Common do-DMA epilogue.
    12181224 *
    1219  * @param   pThis           The shared HDA device state.
    1220  * @param   pThisCC         The ring-3 HDA device state.
    1221  * @param   pStreamShared   HDA stream to update (shared).
    1222  * @param   cbProcessed     The number of bytes processed.
    1223  */
    1224 DECLINLINE(void) hdaR3StreamDoDmaEpilogue(PHDASTATE pThis, PHDASTATER3 pThisCC, PHDASTREAM pStreamShared, uint32_t cbProcessed)
    1225 {
    1226     /*
    1227      * Clear the (pointless) FIFORDY bit again.
    1228      */
    1229     HDA_STREAM_REG(pThis, STS, pStreamShared->u8SD) &= ~HDA_SDSTS_FIFORDY;
    1230 
    1231     /*
    1232      * Try updating the wall clock.
    1233      *
    1234      * Note 1) Only certain guests (like Linux' snd_hda_intel) rely on the WALCLK register
    1235      *         in order to determine the correct timing of the sound device. Other guests
    1236      *         like Windows 7 + 10 (or even more exotic ones like Haiku) will completely
    1237      *         ignore this.
    1238      *
    1239      * Note 2) When updating the WALCLK register too often / early (or even in a non-monotonic
    1240      *         fashion) this *will* upset guest device drivers and will completely fuck up the
    1241      *         sound output. Running VLC on the guest will tell!
    1242      */
    1243     uint32_t const cFramesProcessed = PDMAudioPropsBytesToFrames(&pStreamShared->State.Cfg.Props, cbProcessed);
    1244     /** @todo this needs to go, but we need it for hdaR3WalClkGetMax below. */
    1245     hdaR3StreamPeriodInc(&pStreamShared->State.Period,
    1246                          RT_MIN(cFramesProcessed, hdaR3StreamPeriodGetRemainingFrames(&pStreamShared->State.Period)));
    1247 
    1248     uint64_t const cWallTicks = hdaR3StreamPeriodFramesToWalClk(&pStreamShared->State.Period, cFramesProcessed);
    1249     uint64_t const uWallNew   = hdaWalClkGetCurrent(pThis) + cWallTicks;
    1250     uint64_t const uWallMax   = hdaR3WalClkGetMax(pThis, pThisCC);
    1251     bool const     fWalClkSet = hdaR3WalClkSet(pThis, pThisCC, RT_MIN(uWallNew, uWallMax), false /* fForce */);
    1252     RT_NOREF(fWalClkSet);
    1253 }
    1254 
    1255 /**
    1256  * Completes a BDLE at the end of a DMA loop iteration, if possible.
    1257  *
    12581225 * @param   pDevIns         The device instance.
    12591226 * @param   pThis           The shared HDA device state.
    1260  * @param   pThisCC         The ring-3 HDA device state.
    12611227 * @param   pStreamShared   HDA stream to update (shared).
    1262  * @param   pStreamR3       HDA stream to update (ring-3).
     1228 */
     1229DECLINLINE(void) hdaR3StreamDoDmaEpilogue(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTREAM pStreamShared)
     1230{
     1231    /*
     1232     * Clear the (pointless) FIFORDY bit again.
     1233     */
     1234    HDA_STREAM_REG(pThis, STS, pStreamShared->u8SD) &= ~HDA_SDSTS_FIFORDY;
     1235
     1236    /*
     1237     * We must update this in the epilogue rather than in the prologue
     1238     * as it is used for WALCLK calculation and we must make sure the
     1239     * guest doesn't think we've processed the current period till we
     1240     * actually have.
     1241     */
     1242    pStreamShared->State.tsTransferLast = PDMDevHlpTimerGet(pDevIns, pStreamShared->hTimer);
     1243}
     1244
     1245/**
     1246 * Completes a BDLE at the end of a DMA loop iteration, if possible.
     1247 *
     1248 * @param   pDevIns         The device instance.
     1249 * @param   pThis           The shared HDA device state.
     1250 * @param   pStreamShared   HDA stream to update (shared).
    12631251 * @param   pszFunction     The function name (for logging).
    12641252 */
    1265 DECLINLINE(void) hdaR3StreamDoDmaMaybeCompleteBuffer(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTATER3 pThisCC,
    1266                                                      PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3, const char *pszFunction)
     1253DECLINLINE(void) hdaR3StreamDoDmaMaybeCompleteBuffer(PPDMDEVINS pDevIns, PHDASTATE pThis,
     1254                                                     PHDASTREAM pStreamShared, const char *pszFunction)
    12671255{
    12681256    RT_NOREF(pszFunction);
     
    12771265              pStreamShared->State.aBdl[pStreamShared->State.idxCurBdle].cb,
    12781266              pStreamShared->State.aBdl[pStreamShared->State.idxCurBdle].fFlags));
    1279 
    1280         /* Make sure to also update the wall clock when a BDLE is complete.
    1281          * Needed for Windows 10 guests. */
    1282         /** @todo there is a rounding error here.   */
    1283         hdaR3WalClkSet(pThis, pThisCC,
    1284                          hdaWalClkGetCurrent(pThis)
    1285                        + hdaR3StreamPeriodFramesToWalClk(&pStreamShared->State.Period,
    1286                                                            hdaR3StreamDmaBufGetSize(pStreamShared)
    1287                                                          / pStreamR3->State.Mapping.cbGuestFrame),
    1288                        false /* fForce */);
    12891267
    12901268        /*
     
    13381316 * @param   pDevIns             The device instance.
    13391317 * @param   pThis               The shared HDA device state.
    1340  * @param   pThisCC             The ring-3 HDA device state.
    13411318 * @param   pStreamShared       HDA stream to update (shared).
    13421319 * @param   pStreamR3           HDA stream to update (ring-3).
     
    13541331 * @remarks Caller owns the stream lock.
    13551332 */
    1356 static void hdaR3StreamDoDmaInput(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTATER3 pThisCC, PHDASTREAM pStreamShared,
     1333static void hdaR3StreamDoDmaInput(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTREAM pStreamShared,
    13571334                                  PHDASTREAMR3 pStreamR3, uint32_t cbToConsume, bool fWriteSilence, uint64_t tsNowNs)
    13581335{
     
    13631340     * Common prologue.
    13641341     */
    1365     if (hdaR3StreamDoDmaPrologue(pDevIns, pThis, pStreamShared, uSD, tsNowNs, "hdaR3StreamDoDmaInput"))
     1342    if (hdaR3StreamDoDmaPrologue(pThis, pStreamShared, uSD, tsNowNs, "hdaR3StreamDoDmaInput"))
    13661343    { /* likely */ }
    13671344    else
     
    15361513         * Complete the buffer if necessary (common with the output DMA code).
    15371514         */
    1538         hdaR3StreamDoDmaMaybeCompleteBuffer(pDevIns, pThis, pThisCC, pStreamShared, pStreamR3, "hdaR3StreamDoDmaInput");
     1515        hdaR3StreamDoDmaMaybeCompleteBuffer(pDevIns, pThis, pStreamShared, "hdaR3StreamDoDmaInput");
    15391516    }
    15401517
     
    15451522     * Common epilogue.
    15461523     */
    1547     hdaR3StreamDoDmaEpilogue(pThis, pThisCC, pStreamShared, cbToConsume);
     1524    hdaR3StreamDoDmaEpilogue(pDevIns, pThis, pStreamShared);
    15481525
    15491526    /*
     
    16381615 * @param   pDevIns             The device instance.
    16391616 * @param   pThis               The shared HDA device state.
    1640  * @param   pThisCC             The ring-3 HDA device state.
    16411617 * @param   pStreamShared       HDA stream to update (shared).
    16421618 * @param   pStreamR3           HDA stream to update (ring-3).
     
    16491625 * @remarks Caller owns the stream lock.
    16501626 */
    1651 static void hdaR3StreamDoDmaOutput(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTATER3 pThisCC, PHDASTREAM pStreamShared,
     1627static void hdaR3StreamDoDmaOutput(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTREAM pStreamShared,
    16521628                                   PHDASTREAMR3 pStreamR3, uint32_t cbToProduce, uint64_t tsNowNs)
    16531629{
     
    16581634     * Common prologue.
    16591635     */
    1660     if (hdaR3StreamDoDmaPrologue(pDevIns, pThis, pStreamShared, uSD, tsNowNs, "hdaR3StreamDoDmaOutput"))
     1636    if (hdaR3StreamDoDmaPrologue(pThis, pStreamShared, uSD, tsNowNs, "hdaR3StreamDoDmaOutput"))
    16611637    { /* likely */ }
    16621638    else
     
    18211797         * Complete the buffer if necessary (common with the output DMA code).
    18221798         */
    1823         hdaR3StreamDoDmaMaybeCompleteBuffer(pDevIns, pThis, pThisCC, pStreamShared, pStreamR3, "hdaR3StreamDoDmaOutput");
     1799        hdaR3StreamDoDmaMaybeCompleteBuffer(pDevIns, pThis, pStreamShared, "hdaR3StreamDoDmaOutput");
    18241800    }
    18251801
     
    18301806     * Common epilogue.
    18311807     */
    1832     hdaR3StreamDoDmaEpilogue(pThis, pThisCC, pStreamShared, cbToProduce);
     1808    hdaR3StreamDoDmaEpilogue(pDevIns, pThis, pStreamShared);
    18331809
    18341810    /*
     
    19911967                       PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3, bool fInTimer)
    19921968{
     1969    RT_NOREF(pThisCC);
    19931970    int rc2;
    19941971
     
    20812058
    20822059            uint64_t const offWriteBefore = pStreamR3->State.offWrite;
    2083             hdaR3StreamDoDmaOutput(pDevIns, pThis, pThisCC, pStreamShared, pStreamR3, RT_MIN(cbStreamFree, cbPeriod), tsNowNs);
     2060            hdaR3StreamDoDmaOutput(pDevIns, pThis, pStreamShared, pStreamR3, RT_MIN(cbStreamFree, cbPeriod), tsNowNs);
    20842061
    20852062# ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
     
    22792256# endif
    22802257
    2281                 hdaR3StreamDoDmaInput(pDevIns, pThis, pThisCC, pStreamShared, pStreamR3,
     2258                hdaR3StreamDoDmaInput(pDevIns, pThis, pStreamShared, pStreamR3,
    22822259                                      RT_MIN(cbStreamUsed, cbPeriod), fWriteSilence, tsNowNs);
    22832260
  • trunk/src/VBox/Devices/Audio/HDAStream.h

    r88165 r88170  
    2424#include "DevHDACommon.h"
    2525#include "HDAStreamMap.h"
    26 #include "HDAStreamPeriod.h"
    2726
    2827
     
    134133    uint32_t                cbInputPreBuffer;
    135134    uint32_t                u32Padding2;
    136     /** Timestamp (absolute, in timer ticks) of the last DMA data transfer. */
    137     uint64_t                tsTransferLast;
     135    /** Timestamp (absolute, in timer ticks) of the last DMA data transfer.
     136     * @note This is used for wall clock (WALCLK) calculations.  */
     137    uint64_t volatile       tsTransferLast;
    138138    /** Timestamp (absolute, in timer ticks) of the next DMA data transfer.
    139139     *  Next for determining the next scheduling window.
     
    145145    /** The size of an average transfer. */
    146146    uint32_t                cbAvgTransfer;
    147     /** The stream's period. Need for timing. */
    148     HDASTREAMPERIOD         Period;
    149147    /** The stream's current host side configuration.
    150148     * This should match the SDnFMT in all respects but maybe the channel count as
     
    164162    /** The start time for the playback (on the timer clock). */
    165163    uint64_t                tsStart;
    166 
    167     uint64_t                au64Padding[3];
    168164
    169165    /** @name DMA engine
     
    217213} HDASTREAMSTATE;
    218214AssertCompileSizeAlignment(HDASTREAMSTATE, 8);
     215AssertCompileMemberAlignment(HDASTREAMSTATE, aBdl, 8);
    219216AssertCompileMemberAlignment(HDASTREAMSTATE, aBdl, 16);
    220217AssertCompileMemberAlignment(HDASTREAMSTATE, aSchedule, 16);
     
    273270#ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
    274271    /** Pad the structure size to a 64 byte alignment. */
    275     uint64_t                    au64Padding1[2];
     272    uint64_t                    au64Padding1[4];
    276273    /** Critical section for serialize access to the stream state between the async
    277274     * I/O thread and (basically) the guest. */
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