Changeset 88170 in vbox for trunk/src/VBox/Devices/Audio
- Timestamp:
- Mar 18, 2021 1:38:31 AM (4 years ago)
- svn:sync-xref-src-repo-rev:
- 143321
- Location:
- trunk/src/VBox/Devices/Audio
- Files:
-
- 2 deleted
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Audio/DevHDA.cpp
r88168 r88170 59 59 #include "HDAStream.h" 60 60 #include "HDAStreamMap.h" 61 #include "HDAStreamPeriod.h"62 61 63 62 #include "DrvAudio.h" … … 534 533 }; 535 534 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 546 535 /** HDABDLE field descriptors for the v1 thru v4 saved states. */ 547 536 static SSMFIELD const g_aSSMStreamBdleFields1234[] = … … 1154 1143 } 1155 1144 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 */ 1154 static 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 1156 1206 static VBOXSTRICTRC hdaRegReadWALCLK(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value) 1157 1207 { 1158 1208 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); 1163 1210 return VINF_SUCCESS; 1164 1211 } … … 1431 1478 pThisCC->cStreamsActive++; 1432 1479 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 1442 1480 /** @todo move this into a HDAStream.cpp function. */ 1443 1481 uint64_t tsNow; … … 1452 1490 /* Input streams: Arm the timer and kick the AIO thread. */ 1453 1491 tsNow = PDMDevHlpTimerGet(pDevIns, pStreamShared->hTimer); 1492 pStreamShared->State.tsTransferLast = tsNow; /* for WALCLK */ 1493 1454 1494 uint64_t tsTransferNext = tsNow + pStreamShared->State.aSchedule[0].cPeriodTicks; 1455 1495 pStreamShared->State.tsTransferNext = tsTransferNext; /* legacy */ … … 1457 1497 Log3Func(("[SD%RU8] tsTransferNext=%RU64 (in %RU64)\n", 1458 1498 pStreamShared->u8SD, tsTransferNext, tsTransferNext - tsNow)); 1499 1459 1500 int rc = PDMDevHlpTimerSet(pDevIns, pStreamShared->hTimer, tsTransferNext); 1460 1501 AssertRC(rc); … … 1471 1512 if (pThisCC->cStreamsActive) 1472 1513 pThisCC->cStreamsActive--; 1473 1474 /* Reset the period. */1475 hdaR3StreamPeriodReset(&pStreamShared->State.Period);1476 1514 1477 1515 hdaR3StreamMarkStopped(pStreamShared); … … 2918 2956 HDA_REG(pThis, STATESTS) = 0x1; 2919 2957 2958 /* Reset the wall clock. */ 2959 pThis->tsWalClkStart = PDMDevHlpTimerGet(pDevIns, pThis->aStreams[0].hTimer); 2960 2920 2961 LogFlowFuncLeave(); 2921 2962 LogRel(("HDA: Reset\n")); … … 3402 3443 AssertRCReturn(rc, rc); 3403 3444 3404 rc = pHlp->pfnSSMPutStructEx(pSSM, &pStreamShared->State.Period, sizeof(pStreamShared->State.Period),3405 0 /* fFlags */, g_aSSMStreamPeriodFields7, NULL);3406 AssertRCReturn(rc, rc);3407 3408 3445 uint32_t cbCircBufSize = 0; 3409 3446 uint32_t cbCircBufUsed = 0; … … 3475 3512 3476 3513 /* Save controller-specifc internals. */ 3477 pHlp->pfnSSMPutU64(pSSM, pThis-> u64WalClk);3514 pHlp->pfnSSMPutU64(pSSM, pThis->tsWalClkStart); 3478 3515 pHlp->pfnSSMPutU8(pSSM, pThis->u8IRQL); 3479 3516 … … 3526 3563 hdaR3StreamAsyncIOEnable(pStreamR3, true /* fEnable */); 3527 3564 #endif 3528 /* Resume the stream's period. */3529 hdaR3StreamPeriodResume(&pStreamShared->State.Period);3530 3531 3565 /* (Re-)enable the stream. */ 3532 3566 rc2 = hdaR3StreamEnable(pStreamShared, pStreamR3, true /* fEnable */); … … 3910 3944 || pHlp->pfnSSMHandleVersion(pSSM) >= VBOX_FULL_VERSION_MAKE(5, 2, 0)) 3911 3945 { 3912 pHlp->pfnSSMGetU64(pSSM, &pThis-> u64WalClk);3946 pHlp->pfnSSMGetU64(pSSM, &pThis->tsWalClkStart); /* Was current wall clock */ 3913 3947 rc = pHlp->pfnSSMGetU8(pSSM, &pThis->u8IRQL); 3914 3948 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 } 3915 3960 } 3916 3961 … … 3975 4020 * Load period state. 3976 4021 */ 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 } 3983 4036 3984 4037 /* … … 4137 4190 4138 4191 /** Worker for hdaR3DbgInfo. */ 4139 static void hdaR3DbgPrintRegister(P HDASTATE pThis, PCDBGFINFOHLP pHlp, int iHdaIndex)4192 static void hdaR3DbgPrintRegister(PPDMDEVINS pDevIns, PHDASTATE pThis, PCDBGFINFOHLP pHlp, int iHdaIndex) 4140 4193 { 4141 4194 /** @todo HDA_REG_IDX_NOMEM & GCAP both uses mem_idx zero, no flag or anything to tell them appart. */ … … 4143 4196 pHlp->pfnPrintf(pHlp, "%s: 0x%x\n", g_aHdaRegMap[iHdaIndex].abbrev, pThis->au32Regs[g_aHdaRegMap[iHdaIndex].mem_idx]); 4144 4197 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)); 4146 4199 } 4147 4200 … … 4154 4207 int idxReg = hdaR3DbgLookupRegByName(pszArgs); 4155 4208 if (idxReg != -1) 4156 hdaR3DbgPrintRegister(p This, pHlp, idxReg);4209 hdaR3DbgPrintRegister(pDevIns, pThis, pHlp, idxReg); 4157 4210 else 4158 4211 for (idxReg = 0; idxReg < HDA_NUM_REGS; ++idxReg) 4159 hdaR3DbgPrintRegister(p This, pHlp, idxReg);4212 hdaR3DbgPrintRegister(pDevIns, pThis, pHlp, idxReg); 4160 4213 } 4161 4214 … … 5031 5084 for (size_t i = 0; i < HDA_MAX_STREAMS; i++) 5032 5085 { 5086 /* We need the first timer in ring-0 to calculate the wall clock (WALCLK) time. */ 5033 5087 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), 5035 5089 s_apszNames[i], &pThis->aStreams[i].hTimer); 5036 5090 AssertRCReturn(rc, rc); -
trunk/src/VBox/Devices/Audio/DevHDA.h
r88164 r88170 31 31 #include "HDAStream.h" 32 32 #include "HDAStreamMap.h" 33 #include "HDAStreamPeriod.h"34 33 35 34 #ifdef DEBUG_andy … … 119 118 /** Current IRQ level. */ 120 119 uint8_t u8IRQL; 121 #ifdef VBOX_STRICT122 /** Wall clock (WALCLK) stale count.123 * This indicates the number of set wall clock values which did not actually124 * move the counter forward (stale). */125 uint8_t u8WalClkStaleCnt;126 #else127 uint8_t bPadding1;128 #endif129 uint8_t bPadding2;130 120 /** The device timer Hz rate. Defaults to HDA_TIMER_HZ_DEFAULT. */ 131 121 uint16_t uTimerHz; … … 139 129 * The actual buffer size in bytes will depend on the actual stream configuration. */ 140 130 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; 144 133 /** The CORB buffer. */ 145 134 uint32_t au32CorbBuf[HDA_CORB_SIZE]; -
trunk/src/VBox/Devices/Audio/DevHDACommon.cpp
r88137 r88170 104 104 } 105 105 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 120 106 #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.pStreamShared149 ? hdaR3StreamPeriodGetAbsElapsedWalClk(&pThisCC->SinkFront.pStreamShared->State.Period) : 0;150 # ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND151 # error "Implement me!"152 # endif153 const uint64_t u64LineInAbsWalClk = pThisCC->SinkLineIn.pStreamShared154 ? hdaR3StreamPeriodGetAbsElapsedWalClk(&pThisCC->SinkLineIn.pStreamShared->State.Period) : 0;155 # ifdef VBOX_WITH_HDA_MIC_IN156 const uint64_t u64MicInAbsWalClk = pThisCC->SinkMicIn.pStreamShared157 ? hdaR3StreamPeriodGetAbsElapsedWalClk(&pThisCC->SinkMicIn.pStreamShared->State.Period) : 0;158 # endif159 160 uint64_t u64WalClkNew = RT_MAX(u64WalClkCur, u64FrontAbsWalClk);161 # ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND162 # error "Implement me!"163 # endif164 u64WalClkNew = RT_MAX(u64WalClkNew, u64LineInAbsWalClk);165 # ifdef VBOX_WITH_HDA_MIC_IN166 u64WalClkNew = RT_MAX(u64WalClkNew, u64MicInAbsWalClk);167 # endif168 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 all178 * handled HDA streams have passed (in time) that value. This guarantees that the WALCLK179 * 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_SURROUND192 # error "Implement me!"193 # endif194 195 const bool fLineInPassed = hdaR3StreamPeriodHasPassedAbsWalClk (hdaR3SinkToStreamPeriod(&pThisCC->SinkLineIn), u64WalClk);196 const uint64_t u64LineInAbsWalClk = hdaR3StreamPeriodGetAbsElapsedWalClk(hdaR3SinkToStreamPeriod(&pThisCC->SinkLineIn));197 # ifdef VBOX_WITH_HDA_MIC_IN198 const bool fMicInPassed = hdaR3StreamPeriodHasPassedAbsWalClk (hdaR3SinkToStreamPeriod(&pThisCC->SinkMicIn), u64WalClk);199 const uint64_t u64MicInAbsWalClk = hdaR3StreamPeriodGetAbsElapsedWalClk(hdaR3SinkToStreamPeriod(&pThisCC->SinkMicIn));200 # endif201 202 # ifdef VBOX_STRICT203 const uint64_t u64WalClkCur = ASMAtomicReadU64(&pThis->u64WalClk);204 # endif205 206 /* Only drive the WALCLK register forward if all (active) stream periods have passed207 * the specified point in time given by u64WalClk. */208 if ( ( fFrontPassed209 # ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND210 # error "Implement me!"211 # endif212 && fLineInPassed213 # ifdef VBOX_WITH_HDA_MIC_IN214 && fMicInPassed215 # endif216 )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_SURROUND225 # error "Implement me!"226 # endif227 u64WalClk = RT_MAX(u64WalClk, u64LineInAbsWalClk);228 # ifdef VBOX_WITH_HDA_MIC_IN229 u64WalClk = RT_MAX(u64WalClk, u64MicInAbsWalClk);230 # endif231 232 # ifdef VBOX_STRICT233 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 else243 pThis->u8WalClkStaleCnt = 0;244 # endif245 }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 260 107 /** 261 108 * Returns the default (mixer) sink from a given SD#. … … 299 146 return NULL; 300 147 } 301 302 148 #endif /* IN_RING3 */ 303 149 -
trunk/src/VBox/Devices/Audio/DevHDACommon.h
r88164 r88170 595 595 /** @} */ 596 596 597 /** @name Wall clock (WALCLK) functions.598 * @{599 */600 uint64_t hdaWalClkGetCurrent(PHDASTATE pThis);601 #ifdef IN_RING3602 uint64_t hdaR3WalClkGetMax(PHDASTATE pThis, PHDASTATER3 pThisCC);603 bool hdaR3WalClkSet(PHDASTATE pThis, PHDASTATER3 pThisCC, uint64_t u64WalClk, bool fForce);604 #endif605 /** @} */606 607 597 /** @name Register functions. 608 598 * @{ -
trunk/src/VBox/Devices/Audio/HDACodec.h
r87799 r88170 985 985 /** @name DevHDA saved state versions 986 986 * @{ */ 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 987 992 /** Added (Controller): Current wall clock value (this independent from WALCLK register value). 988 993 * Added (Controller): Current IRQ level. … … 992 997 * Added (Current BDLE per stream): Struct g_aSSMBDLEDescFields7. 993 998 * Added (Current BDLE per stream): Struct g_aSSMBDLEStateFields7. */ 994 #define HDA_SAVED_STATE_VERSION 999 #define HDA_SAVED_STATE_VERSION_7 7 995 1000 /** Saves the current BDLE state. 996 1001 * @since 5.0.14 (r104839) */ -
trunk/src/VBox/Devices/Audio/HDAStream.cpp
r88166 r88170 87 87 #endif 88 88 89 rc = hdaR3StreamPeriodCreate(&pStreamShared->State.Period);90 AssertRCReturn(rc, rc);91 92 89 #ifdef DEBUG 93 90 rc = RTCritSectInit(&pStreamR3->Dbg.CritSect); … … 195 192 pStreamR3->State.pCircBuf = NULL; 196 193 } 197 198 hdaR3StreamPeriodDestroy(&pStreamShared->State.Period);199 194 200 195 #ifdef DEBUG … … 852 847 pStreamR3->State.offRead = 0; 853 848 854 /* Reset the stream's period. */855 hdaR3StreamPeriodReset(&pStreamShared->State.Period);856 857 849 #ifdef DEBUG 858 850 pStreamR3->Dbg.cReadsTotal = 0; … … 936 928 if (RT_SUCCESS(rc)) 937 929 { 930 if (fEnable) 931 pStreamShared->State.tsTransferLast = 0; /* Make sure it's not stale and messes up WALCLK calculations. */ 938 932 pStreamShared->State.fRunning = fEnable; 939 933 } … … 1054 1048 return (uint32_t)RTCircBufFree(pStreamR3->State.pCircBuf); 1055 1049 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 */ 1059 DECLINLINE(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); 1056 1063 } 1057 1064 … … 1151 1158 * @param pszFunction The function name (for logging). 1152 1159 */ 1153 DECLINLINE(bool) hdaR3StreamDoDmaPrologue(P PDMDEVINS pDevIns, PHDASTATE pThis, PHDASTREAM pStreamShared, uint8_t uSD,1160 DECLINLINE(bool) hdaR3StreamDoDmaPrologue(PHDASTATE pThis, PHDASTREAM pStreamShared, uint8_t uSD, 1154 1161 uint64_t tsNowNs, const char *pszFunction) 1155 1162 { … … 1199 1206 Log3(("%s: [SD%RU8] tsDeltaNs=%'RU64 ns\n", pszFunction, uSD, tsNowNs - pStreamShared->State.tsLastTransferNs)); 1200 1207 pStreamShared->State.tsLastTransferNs = tsNowNs; 1201 pStreamShared->State.tsTransferLast = PDMDevHlpTimerGet(pDevIns, pStreamShared->hTimer);1202 1208 1203 1209 /* … … 1217 1223 * Common do-DMA epilogue. 1218 1224 * 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 register1235 * in order to determine the correct timing of the sound device. Other guests1236 * like Windows 7 + 10 (or even more exotic ones like Haiku) will completely1237 * ignore this.1238 *1239 * Note 2) When updating the WALCLK register too often / early (or even in a non-monotonic1240 * fashion) this *will* upset guest device drivers and will completely fuck up the1241 * 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 *1258 1225 * @param pDevIns The device instance. 1259 1226 * @param pThis The shared HDA device state. 1260 * @param pThisCC The ring-3 HDA device state.1261 1227 * @param pStreamShared HDA stream to update (shared). 1262 * @param pStreamR3 HDA stream to update (ring-3). 1228 */ 1229 DECLINLINE(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). 1263 1251 * @param pszFunction The function name (for logging). 1264 1252 */ 1265 DECLINLINE(void) hdaR3StreamDoDmaMaybeCompleteBuffer(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTATER3 pThisCC,1266 PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3,const char *pszFunction)1253 DECLINLINE(void) hdaR3StreamDoDmaMaybeCompleteBuffer(PPDMDEVINS pDevIns, PHDASTATE pThis, 1254 PHDASTREAM pStreamShared, const char *pszFunction) 1267 1255 { 1268 1256 RT_NOREF(pszFunction); … … 1277 1265 pStreamShared->State.aBdl[pStreamShared->State.idxCurBdle].cb, 1278 1266 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 */);1289 1267 1290 1268 /* … … 1338 1316 * @param pDevIns The device instance. 1339 1317 * @param pThis The shared HDA device state. 1340 * @param pThisCC The ring-3 HDA device state.1341 1318 * @param pStreamShared HDA stream to update (shared). 1342 1319 * @param pStreamR3 HDA stream to update (ring-3). … … 1354 1331 * @remarks Caller owns the stream lock. 1355 1332 */ 1356 static void hdaR3StreamDoDmaInput(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDAST ATER3 pThisCC, PHDASTREAM pStreamShared,1333 static void hdaR3StreamDoDmaInput(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTREAM pStreamShared, 1357 1334 PHDASTREAMR3 pStreamR3, uint32_t cbToConsume, bool fWriteSilence, uint64_t tsNowNs) 1358 1335 { … … 1363 1340 * Common prologue. 1364 1341 */ 1365 if (hdaR3StreamDoDmaPrologue(p DevIns, pThis, pStreamShared, uSD, tsNowNs, "hdaR3StreamDoDmaInput"))1342 if (hdaR3StreamDoDmaPrologue(pThis, pStreamShared, uSD, tsNowNs, "hdaR3StreamDoDmaInput")) 1366 1343 { /* likely */ } 1367 1344 else … … 1536 1513 * Complete the buffer if necessary (common with the output DMA code). 1537 1514 */ 1538 hdaR3StreamDoDmaMaybeCompleteBuffer(pDevIns, pThis, p ThisCC, pStreamShared, pStreamR3, "hdaR3StreamDoDmaInput");1515 hdaR3StreamDoDmaMaybeCompleteBuffer(pDevIns, pThis, pStreamShared, "hdaR3StreamDoDmaInput"); 1539 1516 } 1540 1517 … … 1545 1522 * Common epilogue. 1546 1523 */ 1547 hdaR3StreamDoDmaEpilogue(p This, pThisCC, pStreamShared, cbToConsume);1524 hdaR3StreamDoDmaEpilogue(pDevIns, pThis, pStreamShared); 1548 1525 1549 1526 /* … … 1638 1615 * @param pDevIns The device instance. 1639 1616 * @param pThis The shared HDA device state. 1640 * @param pThisCC The ring-3 HDA device state.1641 1617 * @param pStreamShared HDA stream to update (shared). 1642 1618 * @param pStreamR3 HDA stream to update (ring-3). … … 1649 1625 * @remarks Caller owns the stream lock. 1650 1626 */ 1651 static void hdaR3StreamDoDmaOutput(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDAST ATER3 pThisCC, PHDASTREAM pStreamShared,1627 static void hdaR3StreamDoDmaOutput(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTREAM pStreamShared, 1652 1628 PHDASTREAMR3 pStreamR3, uint32_t cbToProduce, uint64_t tsNowNs) 1653 1629 { … … 1658 1634 * Common prologue. 1659 1635 */ 1660 if (hdaR3StreamDoDmaPrologue(p DevIns, pThis, pStreamShared, uSD, tsNowNs, "hdaR3StreamDoDmaOutput"))1636 if (hdaR3StreamDoDmaPrologue(pThis, pStreamShared, uSD, tsNowNs, "hdaR3StreamDoDmaOutput")) 1661 1637 { /* likely */ } 1662 1638 else … … 1821 1797 * Complete the buffer if necessary (common with the output DMA code). 1822 1798 */ 1823 hdaR3StreamDoDmaMaybeCompleteBuffer(pDevIns, pThis, p ThisCC, pStreamShared, pStreamR3, "hdaR3StreamDoDmaOutput");1799 hdaR3StreamDoDmaMaybeCompleteBuffer(pDevIns, pThis, pStreamShared, "hdaR3StreamDoDmaOutput"); 1824 1800 } 1825 1801 … … 1830 1806 * Common epilogue. 1831 1807 */ 1832 hdaR3StreamDoDmaEpilogue(p This, pThisCC, pStreamShared, cbToProduce);1808 hdaR3StreamDoDmaEpilogue(pDevIns, pThis, pStreamShared); 1833 1809 1834 1810 /* … … 1991 1967 PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3, bool fInTimer) 1992 1968 { 1969 RT_NOREF(pThisCC); 1993 1970 int rc2; 1994 1971 … … 2081 2058 2082 2059 uint64_t const offWriteBefore = pStreamR3->State.offWrite; 2083 hdaR3StreamDoDmaOutput(pDevIns, pThis, p ThisCC, pStreamShared, pStreamR3, RT_MIN(cbStreamFree, cbPeriod), tsNowNs);2060 hdaR3StreamDoDmaOutput(pDevIns, pThis, pStreamShared, pStreamR3, RT_MIN(cbStreamFree, cbPeriod), tsNowNs); 2084 2061 2085 2062 # ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO … … 2279 2256 # endif 2280 2257 2281 hdaR3StreamDoDmaInput(pDevIns, pThis, p ThisCC, pStreamShared, pStreamR3,2258 hdaR3StreamDoDmaInput(pDevIns, pThis, pStreamShared, pStreamR3, 2282 2259 RT_MIN(cbStreamUsed, cbPeriod), fWriteSilence, tsNowNs); 2283 2260 -
trunk/src/VBox/Devices/Audio/HDAStream.h
r88165 r88170 24 24 #include "DevHDACommon.h" 25 25 #include "HDAStreamMap.h" 26 #include "HDAStreamPeriod.h"27 26 28 27 … … 134 133 uint32_t cbInputPreBuffer; 135 134 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; 138 138 /** Timestamp (absolute, in timer ticks) of the next DMA data transfer. 139 139 * Next for determining the next scheduling window. … … 145 145 /** The size of an average transfer. */ 146 146 uint32_t cbAvgTransfer; 147 /** The stream's period. Need for timing. */148 HDASTREAMPERIOD Period;149 147 /** The stream's current host side configuration. 150 148 * This should match the SDnFMT in all respects but maybe the channel count as … … 164 162 /** The start time for the playback (on the timer clock). */ 165 163 uint64_t tsStart; 166 167 uint64_t au64Padding[3];168 164 169 165 /** @name DMA engine … … 217 213 } HDASTREAMSTATE; 218 214 AssertCompileSizeAlignment(HDASTREAMSTATE, 8); 215 AssertCompileMemberAlignment(HDASTREAMSTATE, aBdl, 8); 219 216 AssertCompileMemberAlignment(HDASTREAMSTATE, aBdl, 16); 220 217 AssertCompileMemberAlignment(HDASTREAMSTATE, aSchedule, 16); … … 273 270 #ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO 274 271 /** Pad the structure size to a 64 byte alignment. */ 275 uint64_t au64Padding1[ 2];272 uint64_t au64Padding1[4]; 276 273 /** Critical section for serialize access to the stream state between the async 277 274 * I/O thread and (basically) the guest. */
Note:
See TracChangeset
for help on using the changeset viewer.