Changeset 283740 in webkit
- Timestamp:
- Oct 7, 2021 1:36:32 PM (10 months ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 10 edited
-
ChangeLog (modified) (1 diff)
-
Modules/webaudio/AudioListener.cpp (modified) (1 diff)
-
Modules/webaudio/AudioListener.h (modified) (2 diffs)
-
Modules/webaudio/BaseAudioContext.cpp (modified) (1 diff)
-
Modules/webaudio/PannerNode.cpp (modified) (15 diffs)
-
Modules/webaudio/PannerNode.h (modified) (3 diffs)
-
platform/audio/Cone.cpp (modified) (1 diff)
-
platform/audio/Cone.h (modified) (1 diff)
-
platform/audio/Distance.cpp (modified) (3 diffs)
-
platform/audio/Distance.h (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r283736 r283740 1 2021-10-07 Chris Dumez <cdumez@apple.com> 2 3 Cache PannerNode's azimuth, elevation and coneGain 4 https://bugs.webkit.org/show_bug.cgi?id=231314 5 6 Reviewed by Eric Carlson. 7 8 Cache PannerNode's azimuth, elevation and coneGain for better performance. I have noticed while profiling 9 https://downloads.scirra.com/labs/bugs/safaripannerquality/ that PannerNode::process() spends most of its 10 CPU time under PannerNode::calculateAzimuthElevation(). We shouldn't have to re-calculate those properties 11 for every rendering quantum. 12 13 * Modules/webaudio/AudioListener.cpp: 14 (WebCore::AudioListener::updateDirtyState): 15 * Modules/webaudio/AudioListener.h: 16 (WebCore::AudioListener::isPositionDirty const): 17 (WebCore::AudioListener::isOrientationDirty const): 18 (WebCore::AudioListener::isUpVectorDirty const): 19 * Modules/webaudio/BaseAudioContext.cpp: 20 (WebCore::BaseAudioContext::handlePreRenderTasks): 21 * Modules/webaudio/PannerNode.cpp: 22 (WebCore::PannerNode::process): 23 (WebCore::PannerNode::processSampleAccurateValues): 24 (WebCore::PannerNode::setDistanceModelForBindings): 25 (WebCore::PannerNode::setRefDistanceForBindings): 26 (WebCore::PannerNode::setMaxDistanceForBindings): 27 (WebCore::PannerNode::setRolloffFactorForBindings): 28 (WebCore::PannerNode::setConeOuterGainForBindings): 29 (WebCore::PannerNode::setConeOuterAngleForBindings): 30 (WebCore::PannerNode::setConeInnerAngleForBindings): 31 (WebCore::PannerNode::calculateAzimuthElevation): 32 (WebCore::PannerNode::azimuthElevation const): 33 (WebCore::PannerNode::calculateDistanceConeGain): 34 (WebCore::PannerNode::distanceConeGain): 35 (WebCore::PannerNode::invalidateCachedPropertiesIfNecessary): 36 (WebCore::PannerNode::azimuthElevation): Deleted. 37 * Modules/webaudio/PannerNode.h: 38 * platform/audio/Cone.cpp: 39 (WebCore::ConeEffect::gain const): 40 (WebCore::ConeEffect::gain): Deleted. 41 * platform/audio/Cone.h: 42 * platform/audio/Distance.cpp: 43 (WebCore::DistanceEffect::gain const): 44 (WebCore::DistanceEffect::linearGain const): 45 (WebCore::DistanceEffect::inverseGain const): 46 (WebCore::DistanceEffect::exponentialGain const): 47 (WebCore::DistanceEffect::gain): Deleted. 48 (WebCore::DistanceEffect::linearGain): Deleted. 49 (WebCore::DistanceEffect::inverseGain): Deleted. 50 (WebCore::DistanceEffect::exponentialGain): Deleted. 51 * platform/audio/Distance.h: 52 1 53 2021-10-07 Michael Catanzaro <mcatanzaro@gnome.org> 2 54 -
trunk/Source/WebCore/Modules/webaudio/AudioListener.cpp
r275668 r283740 124 124 } 125 125 126 void AudioListener::updateDirtyState() 127 { 128 ASSERT(!isMainThread()); 129 130 auto lastPosition = std::exchange(m_lastPosition, position()); 131 m_isPositionDirty = lastPosition != m_lastPosition; 132 133 auto lastOrientation = std::exchange(m_lastOrientation, orientation()); 134 m_isOrientationDirty = lastOrientation != m_lastOrientation; 135 136 auto lastUpVector = std::exchange(m_lastUpVector, upVector()); 137 m_isUpVectorDirty = lastUpVector != m_lastUpVector; 138 } 139 126 140 const float* AudioListener::positionXValues(size_t framesToProcess) 127 141 { -
trunk/Source/WebCore/Modules/webaudio/AudioListener.h
r277530 r283740 88 88 void updateValuesIfNeeded(size_t framesToProcess); 89 89 90 void updateDirtyState(); 91 bool isPositionDirty() const { return m_isPositionDirty; } 92 bool isOrientationDirty() const { return m_isOrientationDirty; } 93 bool isUpVectorDirty() const { return m_isUpVectorDirty; } 94 90 95 protected: 91 96 explicit AudioListener(BaseAudioContext&); … … 117 122 AudioFloatArray m_upYValues; 118 123 AudioFloatArray m_upZValues; 124 125 FloatPoint3D m_lastPosition; 126 FloatPoint3D m_lastOrientation; 127 FloatPoint3D m_lastUpVector; 128 bool m_isPositionDirty { false }; 129 bool m_isOrientationDirty { false }; 130 bool m_isUpVectorDirty { false }; 119 131 }; 120 132 -
trunk/Source/WebCore/Modules/webaudio/BaseAudioContext.cpp
r282755 r283740 550 550 updateAutomaticPullNodes(); 551 551 m_outputPosition = outputPosition; 552 553 m_listener->updateDirtyState(); 552 554 } 553 555 } -
trunk/Source/WebCore/Modules/webaudio/PannerNode.cpp
r278284 r283740 149 149 } 150 150 151 invalidateCachedPropertiesIfNecessary(); 152 151 153 // Apply the panning effect. 152 double azimuth; 153 double elevation; 154 azimuthElevation(&azimuth, &elevation); 154 auto [azimuth, elevation] = azimuthElevation(); 155 155 m_panner->pan(azimuth, elevation, source, destination, framesToProcess); 156 156 … … 227 227 FloatPoint3D listenerUp(upX[k], upY[k], upZ[k]); 228 228 229 calculateAzimuthElevation(&azimuth[k], &elevation[k], pannerPosition, listenerPosition, listenerFront, listenerUp); 229 auto [calculatedAzimuth, calculatedElevation] = calculateAzimuthElevation(pannerPosition, listenerPosition, listenerFront, listenerUp); 230 azimuth[k] = calculatedAzimuth; 231 elevation[k] = calculatedElevation; 230 232 231 233 // Get distance and cone gain 232 totalGain[k] = calculateDistanceConeGain(pannerPosition, orientation, listenerPosition );234 totalGain[k] = calculateDistanceConeGain(pannerPosition, orientation, listenerPosition, m_distanceEffect, m_coneEffect); 233 235 } 234 236 … … 341 343 Locker locker { m_processLock }; 342 344 345 if (m_distanceEffect.model() == model) 346 return; 347 343 348 m_distanceEffect.setModel(model, true); 349 m_cachedConeGain = std::nullopt; 344 350 } 345 351 … … 354 360 Locker locker { m_processLock }; 355 361 362 if (m_distanceEffect.refDistance() == refDistance) 363 return { }; 364 356 365 m_distanceEffect.setRefDistance(refDistance); 366 m_cachedConeGain = std::nullopt; 357 367 return { }; 358 368 } … … 368 378 Locker locker { m_processLock }; 369 379 380 if (m_distanceEffect.maxDistance() == maxDistance) 381 return { }; 382 370 383 m_distanceEffect.setMaxDistance(maxDistance); 384 m_cachedConeGain = std::nullopt; 371 385 return { }; 372 386 } … … 382 396 Locker locker { m_processLock }; 383 397 398 if (m_distanceEffect.rolloffFactor() == rolloffFactor) 399 return { }; 400 384 401 m_distanceEffect.setRolloffFactor(rolloffFactor); 402 m_cachedConeGain = std::nullopt; 385 403 return { }; 386 404 } … … 396 414 Locker locker { m_processLock }; 397 415 416 if (m_coneEffect.outerGain() == gain) 417 return { }; 418 398 419 m_coneEffect.setOuterGain(gain); 420 m_cachedConeGain = std::nullopt; 399 421 return { }; 400 422 } … … 407 429 Locker locker { m_processLock }; 408 430 431 if (m_coneEffect.outerAngle() == angle) 432 return; 433 409 434 m_coneEffect.setOuterAngle(angle); 435 m_cachedConeGain = std::nullopt; 410 436 } 411 437 … … 417 443 Locker locker { m_processLock }; 418 444 445 if (m_coneEffect.innerAngle() == angle) 446 return; 447 419 448 m_coneEffect.setInnerAngle(angle); 449 m_cachedConeGain = std::nullopt; 420 450 } 421 451 … … 440 470 } 441 471 442 void PannerNode::calculateAzimuthElevation(double* outAzimuth, double* outElevation, const FloatPoint3D& position, const FloatPoint3D& listenerPosition, const FloatPoint3D& listenerFront, const FloatPoint3D& listenerUp) 443 { 444 // FIXME: we should cache azimuth and elevation (if possible), so we only re-calculate if a change has been made. 445 472 auto PannerNode::calculateAzimuthElevation(const FloatPoint3D& position, const FloatPoint3D& listenerPosition, const FloatPoint3D& listenerFront, const FloatPoint3D& listenerUp) -> AzimuthElevation 473 { 446 474 // Calculate the source-listener vector 447 475 FloatPoint3D sourceListener = position - listenerPosition; … … 449 477 if (sourceListener.isZero()) { 450 478 // degenerate case if source and listener are at the same point 451 *outAzimuth = 0.0; 452 *outElevation = 0.0; 453 return; 479 return { }; 454 480 } 455 481 … … 493 519 elevation = -180.0 - elevation; 494 520 495 if (outAzimuth) 496 *outAzimuth = azimuth; 497 if (outElevation) 498 *outElevation = elevation; 499 } 500 501 void PannerNode::azimuthElevation(double* outAzimuth, double* outElevation) 521 return { azimuth, elevation }; 522 } 523 524 auto PannerNode::azimuthElevation() -> const AzimuthElevation& 502 525 { 503 526 ASSERT(context().isAudioThread()); 504 505 calculateAzimuthElevation(outAzimuth, outElevation, position(), listener().position(), listener().orientation(), listener().upVector()); 527 auto& listener = this->listener(); 528 if (!m_cachedAzimuthElevation) 529 m_cachedAzimuthElevation = calculateAzimuthElevation(position(), listener.position(), listener.orientation(), listener.upVector()); 530 return *m_cachedAzimuthElevation; 506 531 } 507 532 … … 517 542 } 518 543 519 float PannerNode::calculateDistanceConeGain(const FloatPoint3D& sourcePosition, const FloatPoint3D& orientation, const FloatPoint3D& listenerPosition )544 float PannerNode::calculateDistanceConeGain(const FloatPoint3D& sourcePosition, const FloatPoint3D& orientation, const FloatPoint3D& listenerPosition, const DistanceEffect& distanceEffect, const ConeEffect& coneEffect) 520 545 { 521 546 double listenerDistance = sourcePosition.distanceTo(listenerPosition); 522 double distanceGain = m_distanceEffect.gain(listenerDistance); 523 524 // FIXME: could optimize by caching coneGain 525 double coneGain = m_coneEffect.gain(sourcePosition, orientation, listenerPosition); 547 double distanceGain = distanceEffect.gain(listenerDistance); 548 double coneGain = coneEffect.gain(sourcePosition, orientation, listenerPosition); 526 549 527 550 return float(distanceGain * coneGain); … … 531 554 { 532 555 ASSERT(context().isAudioThread()); 533 534 return calculateDistanceConeGain(position(), orientation(), listener().position()); 556 if (!m_cachedConeGain) 557 m_cachedConeGain = calculateDistanceConeGain(position(), orientation(), listener().position(), m_distanceEffect, m_coneEffect); 558 return *m_cachedConeGain; 535 559 } 536 560 … … 551 575 } 552 576 577 void PannerNode::invalidateCachedPropertiesIfNecessary() 578 { 579 auto lastPosition = std::exchange(m_lastPosition, position()); 580 bool hasPositionChanged = m_lastPosition != lastPosition; 581 auto lastOrientation = std::exchange(m_lastOrientation, position()); 582 bool hasOrientationChanged = m_lastOrientation != lastOrientation; 583 auto& listener = this->listener(); 584 585 if (hasPositionChanged || listener.isPositionDirty() || listener.isOrientationDirty() || listener.isUpVectorDirty()) 586 m_cachedAzimuthElevation = std::nullopt; 587 588 if (hasPositionChanged || hasOrientationChanged || listener.isPositionDirty()) 589 m_cachedConeGain = std::nullopt; 590 } 591 553 592 } // namespace WebCore 554 593 -
trunk/Source/WebCore/Modules/webaudio/PannerNode.h
r278284 r283740 114 114 PannerNode(BaseAudioContext&, const PannerOptions&); 115 115 116 void calculateAzimuthElevation(double* outAzimuth, double* outElevation, const FloatPoint3D& position, const FloatPoint3D& listenerPosition, const FloatPoint3D& listenerForward, const FloatPoint3D& listenerUp) WTF_REQUIRES_LOCK(m_processLock); 117 float calculateDistanceConeGain(const FloatPoint3D& position, const FloatPoint3D& orientation, const FloatPoint3D& listenerPosition) WTF_REQUIRES_LOCK(m_processLock); 116 struct AzimuthElevation { 117 double azimuth { 0. }; 118 double elevation { 0. }; 119 }; 120 static AzimuthElevation calculateAzimuthElevation(const FloatPoint3D& position, const FloatPoint3D& listenerPosition, const FloatPoint3D& listenerForward, const FloatPoint3D& listenerUp); 121 static float calculateDistanceConeGain(const FloatPoint3D& position, const FloatPoint3D& orientation, const FloatPoint3D& listenerPosition, const DistanceEffect&, const ConeEffect&); 118 122 119 123 // Returns the combined distance and cone gain attenuation. … … 122 126 bool requiresTailProcessing() const final; 123 127 124 void azimuthElevation(double* outAzimuth, double* outElevation) WTF_REQUIRES_LOCK(m_processLock); 128 void invalidateCachedPropertiesIfNecessary() WTF_REQUIRES_LOCK(m_processLock); 129 130 const AzimuthElevation& azimuthElevation() WTF_REQUIRES_LOCK(m_processLock); 125 131 void processSampleAccurateValues(AudioBus* destination, const AudioBus* source, size_t framesToProcess) WTF_REQUIRES_LOCK(m_processLock); 126 132 bool hasSampleAccurateValues() const WTF_REQUIRES_LOCK(m_processLock); … … 146 152 Ref<AudioParam> m_orientationZ WTF_GUARDED_BY_LOCK(m_processLock); 147 153 154 mutable std::optional<AzimuthElevation> m_cachedAzimuthElevation WTF_GUARDED_BY_LOCK(m_processLock); 155 mutable std::optional<float> m_cachedConeGain WTF_GUARDED_BY_LOCK(m_processLock); 156 FloatPoint3D m_lastPosition WTF_GUARDED_BY_LOCK(m_processLock); 157 FloatPoint3D m_lastOrientation WTF_GUARDED_BY_LOCK(m_processLock); 158 148 159 // Synchronize process() with setting of the panning model, source's location 149 160 // information, listener, distance parameters and sound cones. -
trunk/Source/WebCore/platform/audio/Cone.cpp
r267544 r283740 38 38 ConeEffect::ConeEffect() = default; 39 39 40 double ConeEffect::gain(FloatPoint3D sourcePosition, FloatPoint3D sourceOrientation, FloatPoint3D listenerPosition) 40 double ConeEffect::gain(FloatPoint3D sourcePosition, FloatPoint3D sourceOrientation, FloatPoint3D listenerPosition) const 41 41 { 42 42 if (sourceOrientation.isZero() || ((m_innerAngle == 360.0) && (m_outerAngle == 360.0))) -
trunk/Source/WebCore/platform/audio/Cone.h
r267544 r283740 42 42 43 43 // Returns scalar gain for the given source/listener positions/orientations 44 double gain(FloatPoint3D sourcePosition, FloatPoint3D sourceOrientation, FloatPoint3D listenerPosition) ;44 double gain(FloatPoint3D sourcePosition, FloatPoint3D sourceOrientation, FloatPoint3D listenerPosition) const; 45 45 46 46 // Angles in degrees -
trunk/Source/WebCore/platform/audio/Distance.cpp
r267544 r283740 40 40 DistanceEffect::DistanceEffect() = default; 41 41 42 double DistanceEffect::gain(double distance) 42 double DistanceEffect::gain(double distance) const 43 43 { 44 44 // don't go beyond maximum distance … … 61 61 } 62 62 63 double DistanceEffect::linearGain(double distance) 63 double DistanceEffect::linearGain(double distance) const 64 64 { 65 65 auto clampedRolloffFactor = std::clamp(m_rolloffFactor, 0.0, 1.0); … … 69 69 } 70 70 71 double DistanceEffect::inverseGain(double distance) 71 double DistanceEffect::inverseGain(double distance) const 72 72 { 73 73 return m_refDistance / (m_refDistance + m_rolloffFactor * (distance - m_refDistance)); 74 74 } 75 75 76 double DistanceEffect::exponentialGain(double distance) 76 double DistanceEffect::exponentialGain(double distance) const 77 77 { 78 78 return pow(distance / m_refDistance, -m_rolloffFactor); -
trunk/Source/WebCore/platform/audio/Distance.h
r278284 r283740 47 47 48 48 // Returns scalar gain for the given distance the current distance model is used 49 double gain(double distance) ;49 double gain(double distance) const; 50 50 51 51 DistanceModelType model() const { return m_model; } … … 67 67 68 68 protected: 69 double linearGain(double distance) ;70 double inverseGain(double distance) ;71 double exponentialGain(double distance) ;69 double linearGain(double distance) const; 70 double inverseGain(double distance) const; 71 double exponentialGain(double distance) const; 72 72 73 73 DistanceModelType m_model { DistanceModelType::Inverse };
Note: See TracChangeset
for help on using the changeset viewer.