Changeset 89826 in vbox for trunk/src/VBox/Devices/Audio
- Timestamp:
- Jun 21, 2021 9:41:38 PM (4 years ago)
- svn:sync-xref-src-repo-rev:
- 145283
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Audio/DevHdaStream.cpp
r89638 r89826 236 236 /* Figure out the BDLE range for this period. */ 237 237 uint32_t const idxFirstBdle = idx == 0 ? 0 238 : pStreamShared->State.aSchedule[idx - 1].idxFirst 239 + pStreamShared->State.aSchedule[idx - 1].cEntries; 238 : RT_MIN((uint32_t)( pStreamShared->State.aSchedule[idx - 1].idxFirst 239 + pStreamShared->State.aSchedule[idx - 1].cEntries), 240 idxLastBdle); 240 241 241 242 pStreamShared->State.aSchedule[idx].idxFirst = (uint8_t)idxFirstBdle; … … 340 341 uint32_t cbBorrow = 0; 341 342 uint32_t cbCur = 0; 343 uint32_t cbMin = UINT32_MAX; 342 344 pStreamShared->State.aSchedule[0].idxFirst = 0; 343 345 for (uint32_t i = 0; i < cSegments; i++) 344 346 { 345 347 cbCur += pStreamShared->State.aBdl[i].cb; 348 if (pStreamShared->State.aBdl[i].cb < cbMin) 349 cbMin = pStreamShared->State.aBdl[i].cb; 346 350 if (pStreamShared->State.aBdl[i].fFlags & HDA_BDLE_F_IOC) 347 351 { … … 363 367 if (cbCur && cBufferIrqs == 0) 364 368 { 365 /* No IOC. Split the period in two. */ 369 /* 370 * No IOC. Vista ends up here, typically with three buffers configured. 371 * 372 * The perferred option here is to aim at processing one average BDLE with 373 * each DMA timer period, since that best matches how we update LPIB at 374 * present. 375 * 376 * The second alternative is to divide the whole span up into 3-4 periods 377 * to try increase our chances of keeping ahead of the guest. We may need 378 * to pick this if there are too few buffer descriptor or they are too small. 379 * 380 * However, what we probably should be doing is to do real DMA work whenever 381 * the guest reads a DMA related register (like LPIB) and just do 3-4 DMA 382 * timer periods, however we'll be postponing the DMA timer every time we 383 * return to ring-3 and signal the AIO, so in the end we'd probably not use 384 * the timer callback at all. (This is assuming a small shared per-stream 385 * buffer for keeping the DMA data in and that it's size will force a return 386 * to ring-3 often enough to keep the AIO thread going at a reasonable rate.) 387 */ 366 388 Assert(cbCur == cbTotal); 367 cbCur = PDMAudioPropsFloorBytesToFrame(pGuestProps, cbCur / 2); 368 rc = hdaR3StreamAddScheduleItem(pStreamShared, cbCur, cbMaxPeriod, cSegments, pHostProps, pGuestProps, &cbBorrow); 369 ASSERT_GUEST_RC_RETURN(rc, rc); 370 371 rc = hdaR3StreamAddScheduleItem(pStreamShared, cbTotal - cbCur, cbMaxPeriod, cSegments, 372 pHostProps, pGuestProps, &cbBorrow); 373 ASSERT_GUEST_RC_RETURN(rc, rc); 389 390 /* Match the BDLEs 1:1 if there are 3 or more and that the smallest one 391 is at least 5ms big. */ 392 if (cSegments >= 3 && PDMAudioPropsBytesToMilli(pGuestProps, cbMin) >= 5 /*ms*/) 393 { 394 for (uint32_t i = 0; i < cSegments; i++) 395 { 396 rc = hdaR3StreamAddScheduleItem(pStreamShared, pStreamShared->State.aBdl[i].cb, cbMaxPeriod, 397 i, pHostProps, pGuestProps, &cbBorrow); 398 ASSERT_GUEST_RC_RETURN(rc, rc); 399 } 400 } 401 /* Otherwise, just divide the work into 3 or 4 portions and hope for the best. 402 It seems, though, that this only really work for windows vista if we avoid 403 working accross buffer lines. */ 404 /** @todo This can be simplified/relaxed/uncluttered if we do DMA work when LPIB 405 * is read, assuming ofc that LPIB is read before each buffer update. */ 406 else 407 { 408 uint32_t const cPeriods = cSegments != 3 && PDMAudioPropsBytesToMilli(pGuestProps, cbCur) >= 4 * 5 /*ms*/ 409 ? 4 : cSegments != 2 ? 3 : 2; 410 uint32_t const cbPeriod = PDMAudioPropsFloorBytesToFrame(pGuestProps, cbCur / cPeriods); 411 uint32_t iBdle = 0; 412 uint32_t offBdle = 0; 413 for (uint32_t iPeriod = 0; iPeriod < cPeriods; iPeriod++) 414 { 415 if (iPeriod + 1 < cPeriods) 416 { 417 offBdle += cbPeriod; 418 while (iBdle < cSegments && offBdle >= pStreamShared->State.aBdl[iBdle].cb) 419 offBdle -= pStreamShared->State.aBdl[iBdle++].cb; 420 rc = hdaR3StreamAddScheduleItem(pStreamShared, cbPeriod, cbMaxPeriod, offBdle != 0 ? iBdle : iBdle - 1, 421 pHostProps, pGuestProps, &cbBorrow); 422 } 423 else 424 rc = hdaR3StreamAddScheduleItem(pStreamShared, cbCur - iPeriod * cbPeriod, cbMaxPeriod, cSegments - 1, 425 pHostProps, pGuestProps, &cbBorrow); 426 ASSERT_GUEST_RC_RETURN(rc, rc); 427 } 428 429 } 374 430 Assert(cbBorrow == 0); 375 431 } … … 999 1055 { 1000 1056 AssertPtrReturnVoid(pStreamShared); 1001 Assert ReturnVoid (uLPIB <= pStreamShared->u32CBL); /* Make sure that we don't go out-of-bounds. */1057 AssertMsgStmt(uLPIB <= pStreamShared->u32CBL, ("%#x\n", uLPIB), uLPIB = pStreamShared->u32CBL); 1002 1058 1003 1059 Log3Func(("[SD%RU8] LPIB=%RU32 (DMA Position Buffer Enabled: %RTbool)\n", pStreamShared->u8SD, uLPIB, pThis->fDMAPosition)); … … 1033 1089 uint32_t const uCBL = pStreamShared->u32CBL; 1034 1090 if (uCBL) /* paranoia */ 1035 hdaR3StreamSetPositionAbs(pStreamShared, pDevIns, pThis, 1036 (HDA_STREAM_REG(pThis, LPIB, pStreamShared->u8SD) + cbToAdd) % uCBL); 1091 { 1092 uint32_t uNewLpid = HDA_STREAM_REG(pThis, LPIB, pStreamShared->u8SD) + cbToAdd; 1093 #if 1 /** @todo r=bird: this is wrong according to the spec */ 1094 uNewLpid %= uCBL; 1095 #else 1096 /* The spec says it goes to CBL then wraps arpimd to 1, not back to zero. See 3.3.37. */ 1097 if (uNewLpid > uCBL) 1098 uNewLpid %= uCBL; 1099 #endif 1100 hdaR3StreamSetPositionAbs(pStreamShared, pDevIns, pThis, uNewLpid); 1101 } 1037 1102 } 1038 1103 } … … 1264 1329 * 1265 1330 * Do this as accurate and close to the actual data transfer as possible. 1266 * All gue tsts rely on this, depending on the mechanism they use (LPIB register or DMA counters).1331 * All guests rely on this, depending on the mechanism they use (LPIB register or DMA counters). 1267 1332 * 1268 1333 * Note for Windows 10: The OS' driver is *very* picky about *when* the (DMA) positions get updated!
Note:
See TracChangeset
for help on using the changeset viewer.