⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 283322 in webkit


Ignore:
Timestamp:
Sep 30, 2021, 12:23:43 PM (5 years ago)
Author:
Chris Dumez
Message:

Web Audio panner node quality deteriorates over time
https://bugs.webkit.org/show_bug.cgi?id=230950
<rdar://problem/83675934>

Reviewed by Eric Carlson.

When profiling the test case, I noticed what we were spending most of the CPU time
under AudioParamTimeline::valuesForFrameRangeImpl() / isEventCurrent() called from
PannerNode::process(). The reason for that is that the number of events in the
AudioParamTimeline would keep growing unboundedly and it would make the
valuesForFrameRangeImpl() implementation more and more expensive over time, since
it has to iterate over all events.

To address the issue, valuesForFrameRangeImpl() now keeps track of the events
that it had to skip because they were in the past. Then, at the end of the loop,
it removes the outdated events so it won't have to iterate over them the next
time around. This behavior is similar to what Blink does.

  • Modules/webaudio/AudioParamTimeline.cpp:

(WebCore::AudioParamTimeline::removeOldEvents):
(WebCore::AudioParamTimeline::valuesForFrameRangeImpl):

  • Modules/webaudio/AudioParamTimeline.h:
Location:
trunk/Source/WebCore
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r283321 r283322  
     12021-09-30  Chris Dumez  <cdumez@apple.com>
     2
     3        Web Audio panner node quality deteriorates over time
     4        https://bugs.webkit.org/show_bug.cgi?id=230950
     5        <rdar://problem/83675934>
     6
     7        Reviewed by Eric Carlson.
     8
     9        When profiling the test case, I noticed what we were spending most of the CPU time
     10        under AudioParamTimeline::valuesForFrameRangeImpl() / isEventCurrent() called from
     11        PannerNode::process(). The reason for that is that the number of events in the
     12        AudioParamTimeline would keep growing unboundedly and it would make the
     13        valuesForFrameRangeImpl() implementation more and more expensive over time, since
     14        it has to iterate over all events.
     15
     16        To address the issue, valuesForFrameRangeImpl() now keeps track of the events
     17        that it had to skip because they were in the past. Then, at the end of the loop,
     18        it removes the outdated events so it won't have to iterate over them the next
     19        time around. This behavior is similar to what Blink does.
     20
     21        * Modules/webaudio/AudioParamTimeline.cpp:
     22        (WebCore::AudioParamTimeline::removeOldEvents):
     23        (WebCore::AudioParamTimeline::valuesForFrameRangeImpl):
     24        * Modules/webaudio/AudioParamTimeline.h:
     25
    1262021-09-30  Ziran Sun  <zsun@igalia.com>
    227
  • trunk/Source/WebCore/Modules/webaudio/AudioParamTimeline.cpp

    r278253 r283322  
    325325}
    326326
     327void AudioParamTimeline::removeOldEvents(size_t eventCount)
     328{
     329    ASSERT(eventCount <= m_events.size());
     330    if (m_events.isEmpty())
     331        return;
     332
     333    // Always leave at least one event in the list.
     334    m_events.remove(0, std::min(eventCount, m_events.size() - 1));
     335}
     336
    327337std::optional<float> AudioParamTimeline::valueForContextTime(BaseAudioContext& context, float defaultValue, float minValue, float maxValue)
    328338{
     
    398408
    399409    float value = defaultValue;
     410    size_t numberOfSkippedEvents = 0;
    400411
    401412    // Go through each event and render the value buffer where the times overlap,
     
    409420
    410421        // Wait until we get a more recent event.
    411         if (!isEventCurrent(*event, nextEvent, currentFrame, sampleRate))
     422        if (!isEventCurrent(*event, nextEvent, currentFrame, sampleRate)) {
     423            ++numberOfSkippedEvents;
    412424            continue;
     425        }
    413426
    414427        auto nextEventType = nextEvent ? static_cast<ParamEvent::Type>(nextEvent->type()) : ParamEvent::LastType /* unknown */;
     
    482495        }
    483496    }
     497
     498    // Drop outdated events that we skipped so we don't have to go through them again in the future.
     499    if (numberOfSkippedEvents > 0)
     500        removeOldEvents(numberOfSkippedEvents);
    484501
    485502    // If there's any time left after processing the last event then just propagate the last value
  • trunk/Source/WebCore/Modules/webaudio/AudioParamTimeline.h

    r278253 r283322  
    191191
    192192    void removeCancelledEvents(size_t firstEventToRemove) WTF_REQUIRES_LOCK(m_eventsLock);
     193    void removeOldEvents(size_t eventCount) WTF_REQUIRES_LOCK(m_eventsLock);
    193194    ExceptionOr<void> insertEvent(ParamEvent&&) WTF_REQUIRES_LOCK(m_eventsLock);
    194195    float valuesForFrameRangeImpl(size_t startFrame, size_t endFrame, float defaultValue, float* values, unsigned numberOfValues, double sampleRate, double controlRate) WTF_REQUIRES_LOCK(m_eventsLock);
Note: See TracChangeset for help on using the changeset viewer.