Changeset 89664 in vbox
- Timestamp:
- Jun 14, 2021 12:01:16 AM (3 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Audio/DevIchAc97.cpp
r89661 r89664 848 848 RT_BOOL(pRegs->bd.ctl_len & AC97_BD_BUP), 849 849 RT_BOOL(pRegs->bd.ctl_len & AC97_BD_IOC))); 850 /** @todo r=bird: Several of the specificiation states that zero length BDL 851 * entries are okay, as long as they aren't at the head or end. We 852 * should simply skip up to 30 empty ones, because otherwise the timer 853 * locking falls flat on its face. */ 850 854 } 851 855 … … 1679 1683 } 1680 1684 1681 /**1682 * Calculates and returns the ticks for a specified amount of bytes.1683 *1684 * @returns Calculated ticks1685 * @param pDevIns The device instance.1686 * @param pStream AC'97 stream to calculate ticks for (shared).1687 * @param pStreamCC AC'97 stream to calculate ticks for (ring-3).1688 * @param cbBytes Bytes to calculate ticks for.1689 */1690 static uint64_t ichac97R3StreamTransferCalcNext(PPDMDEVINS pDevIns, PAC97STREAM pStream, PAC97STREAMR3 pStreamCC, uint32_t cbBytes)1691 {1692 if (!cbBytes)1693 return 0;1694 1695 /** @todo r=bird: Why use microseconds when the timer clock has been using1696 * nanosecond resolution since early 2005? */1697 const uint64_t usBytes = PDMAudioPropsBytesToMicro(&pStreamCC->State.Cfg.Props, cbBytes);1698 const uint64_t cTransferTicks = PDMDevHlpTimerFromMicro(pDevIns, pStream->hTimer, usBytes);1699 1700 Log3Func(("[SD%RU8] Timer %uHz, cbBytes=%RU32 -> usBytes=%RU64, cTransferTicks=%RU64\n",1701 pStream->u8SD, pStreamCC->State.uTimerHz, cbBytes, usBytes, cTransferTicks));1702 1703 return cTransferTicks;1704 }1705 1685 1706 1686 /** … … 1710 1690 * @param pStream The AC'97 stream to update (shared). 1711 1691 * @param pStreamCC The AC'97 stream to update (ring-3). 1712 * @param cbBytes Bytes to update next transfer for. 1713 */ 1714 static void ichac97R3StreamTransferUpdate(PPDMDEVINS pDevIns, PAC97STREAM pStream, PAC97STREAMR3 pStreamCC, uint32_t cbBytes) 1715 { 1716 if (!cbBytes) 1717 return; 1718 1719 /* Calculate the bytes we need to transfer to / from the stream's DMA per iteration. 1720 * This is bound to the device's Hz rate and thus to the (virtual) timing the device expects. */ 1721 pStreamCC->State.cbTransferChunk = cbBytes; 1722 1723 /* Update the transfer ticks. */ 1724 pStreamCC->State.cTransferTicks = ichac97R3StreamTransferCalcNext(pDevIns, pStream, pStreamCC, 1725 pStreamCC->State.cbTransferChunk); 1726 Assert(pStreamCC->State.cTransferTicks); /* Paranoia. */ 1692 */ 1693 static void ichac97R3StreamTransferUpdate(PPDMDEVINS pDevIns, PAC97STREAM pStream, PAC97STREAMR3 pStreamCC) 1694 { 1695 /* 1696 * Get the number of bytes left in the current buffer. 1697 * 1698 * This isn't entirely optimal iff the current entry doesn't have IOC set, in 1699 * that case we should use the number of bytes to the next IOC. Unfortuantely, 1700 * it seems the spec doesn't allow us to prefetch more than one BDLE, so we 1701 * probably cannot look ahead without violating that restriction. This is 1702 * probably a purely theoretical problem at this point. 1703 */ 1704 uint32_t const cbLeftInBdle = pStream->Regs.picb * PDMAudioPropsSampleSize(&pStreamCC->State.Cfg.Props); 1705 if (cbLeftInBdle > 0) /** @todo r=bird: see todo about this in ichac97R3StreamFetchBDLE. */ 1706 { 1707 /* 1708 * Since the buffer can be up to 0xfffe samples long (frame aligning stereo 1709 * prevents 0xffff), which translates to 743ms at a 44.1kHz rate, we must 1710 * also take the nominal timer frequency into account here so we keep 1711 * moving data at a steady rate. (In theory, I think the guest can even 1712 * set up just one buffer and anticipate where we are in the buffer 1713 * processing when it writes/reads from it. Linux seems to be doing such 1714 * configs when not playing or something.) 1715 */ 1716 uint32_t const cbMaxPerHz = PDMAudioPropsNanoToBytes(&pStreamCC->State.Cfg.Props, RT_NS_1SEC / pStreamCC->State.uTimerHz); 1717 1718 if (cbLeftInBdle <= cbMaxPerHz) 1719 pStreamCC->State.cbTransferChunk = cbLeftInBdle; 1720 /* Try avoid leaving a very short period at the end of a buffer. */ 1721 else if (cbLeftInBdle >= cbMaxPerHz + cbMaxPerHz / 2) 1722 pStreamCC->State.cbTransferChunk = cbMaxPerHz; 1723 else 1724 pStreamCC->State.cbTransferChunk = PDMAudioPropsFloorBytesToFrame(&pStreamCC->State.Cfg.Props, cbLeftInBdle / 2); 1725 1726 /* 1727 * Translate the chunk size to timer ticks. 1728 */ 1729 uint64_t const cNsXferChunk = PDMAudioPropsBytesToNano(&pStreamCC->State.Cfg.Props, pStreamCC->State.cbTransferChunk); 1730 pStreamCC->State.cTransferTicks = PDMDevHlpTimerFromNano(pDevIns, pStream->hTimer, cNsXferChunk); 1731 Assert(pStreamCC->State.cTransferTicks > 0); 1732 1733 Log3Func(("[SD%RU8] cbLeftInBdle=%#RX32 cbMaxPerHz=%#RX32 (%RU16Hz) -> cbTransferChunk=%#RX32 cTransferTicks=%RX64\n", 1734 pStream->u8SD, cbLeftInBdle, cbMaxPerHz, pStreamCC->State.uTimerHz, 1735 pStreamCC->State.cbTransferChunk, pStreamCC->State.cTransferTicks)); 1736 } 1727 1737 } 1728 1738 … … 2487 2497 Assert(PDMDevHlpTimerIsLockOwner(pDevIns, pStream->hTimer)); 2488 2498 2489 ichac97R3StreamUpdateDma(pDevIns, pThis, pThisCC, pStream, pStreamCC);2490 2491 2499 PAUDMIXSINK pSink = ichac97R3IndexToSink(pThisCC, pStream->u8SD); 2492 2500 if (pSink && AudioMixerSinkIsActive(pSink)) 2493 2501 { 2494 ichac97R3StreamTransferUpdate(pDevIns, pStream, pStreamCC, pStream->Regs.picb << 1); /** @todo r=andy Assumes 16-bit samples. */ 2502 ichac97R3StreamUpdateDma(pDevIns, pThis, pThisCC, pStream, pStreamCC); 2503 2504 ichac97R3StreamTransferUpdate(pDevIns, pStream, pStreamCC); 2495 2505 ichac97R3TimerSet(pDevIns, pStream, pStreamCC->State.cTransferTicks); 2496 2506 }
Note:
See TracChangeset
for help on using the changeset viewer.