Title: [274650] trunk/Source/WebCore
Revision
274650
Author
[email protected]
Date
2021-03-18 10:51:00 -0700 (Thu, 18 Mar 2021)

Log Message

Avoid heap allocation under PannerNode::pullInputs()
https://bugs.webkit.org/show_bug.cgi?id=223445

Reviewed by Darin Adler.

PannerNode::pullInputs() was doing a heap allocation on the audio thread when
constructing a HashSet. It turns out that PannerNode::pullInputs() and
PannerNode::notifyAudioSourcesConnectedToNode() were not needed at all in
the modern PannerNode. They were only used to set the PannerNode on
AudioBufferSourceNodes so they could use its dopplerRate. However, the
dopplerRate was only a thing on the legacy WebKitAudioPannerNode. For the
modern PannerNode, there is no dopplerRate so we always end up using 1.0.

To address the issue, I thus completely removed PannerNode's pullInputs &
notifyAudioSourcesConnectedToNode(). I also updated AudioBufferSourceNode
to make it clear it uses a WebKitAudioPannerNode. Finally, I got rid of
the PannerNodeBase base class too since it is no longer needed.

* Modules/webaudio/AudioBufferSourceNode.cpp:
(WebCore::AudioBufferSourceNode::totalPitchRate):
(WebCore::AudioBufferSourceNode::setPannerNode):
(WebCore::AudioBufferSourceNode::clearPannerNode):
(WebCore::AudioBufferSourceNode::finish):
* Modules/webaudio/AudioBufferSourceNode.h:
* Modules/webaudio/PannerNode.cpp:
(WebCore::PannerNode::PannerNode):
* Modules/webaudio/PannerNode.h:
* Modules/webaudio/WebKitAudioPannerNode.cpp:
(WebCore::WebKitAudioPannerNode::WebKitAudioPannerNode):
* Modules/webaudio/WebKitAudioPannerNode.h:

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (274649 => 274650)


--- trunk/Source/WebCore/ChangeLog	2021-03-18 17:25:44 UTC (rev 274649)
+++ trunk/Source/WebCore/ChangeLog	2021-03-18 17:51:00 UTC (rev 274650)
@@ -1,3 +1,36 @@
+2021-03-18  Chris Dumez  <[email protected]>
+
+        Avoid heap allocation under PannerNode::pullInputs()
+        https://bugs.webkit.org/show_bug.cgi?id=223445
+
+        Reviewed by Darin Adler.
+
+        PannerNode::pullInputs() was doing a heap allocation on the audio thread when
+        constructing a HashSet. It turns out that PannerNode::pullInputs() and
+        PannerNode::notifyAudioSourcesConnectedToNode() were not needed at all in
+        the modern PannerNode. They were only used to set the PannerNode on
+        AudioBufferSourceNodes so they could use its dopplerRate. However, the
+        dopplerRate was only a thing on the legacy WebKitAudioPannerNode. For the
+        modern PannerNode, there is no dopplerRate so we always end up using 1.0.
+
+        To address the issue, I thus completely removed PannerNode's pullInputs &
+        notifyAudioSourcesConnectedToNode(). I also updated AudioBufferSourceNode
+        to make it clear it uses a WebKitAudioPannerNode. Finally, I got rid of
+        the PannerNodeBase base class too since it is no longer needed.
+
+        * Modules/webaudio/AudioBufferSourceNode.cpp:
+        (WebCore::AudioBufferSourceNode::totalPitchRate):
+        (WebCore::AudioBufferSourceNode::setPannerNode):
+        (WebCore::AudioBufferSourceNode::clearPannerNode):
+        (WebCore::AudioBufferSourceNode::finish):
+        * Modules/webaudio/AudioBufferSourceNode.h:
+        * Modules/webaudio/PannerNode.cpp:
+        (WebCore::PannerNode::PannerNode):
+        * Modules/webaudio/PannerNode.h:
+        * Modules/webaudio/WebKitAudioPannerNode.cpp:
+        (WebCore::WebKitAudioPannerNode::WebKitAudioPannerNode):
+        * Modules/webaudio/WebKitAudioPannerNode.h:
+
 2021-03-18  Truitt Savell  <[email protected]>
 
         Unreviewed, reverting r274644.

Modified: trunk/Source/WebCore/Modules/webaudio/AudioBufferSourceNode.cpp (274649 => 274650)


--- trunk/Source/WebCore/Modules/webaudio/AudioBufferSourceNode.cpp	2021-03-18 17:25:44 UTC (rev 274649)
+++ trunk/Source/WebCore/Modules/webaudio/AudioBufferSourceNode.cpp	2021-03-18 17:51:00 UTC (rev 274650)
@@ -35,9 +35,9 @@
 #include "AudioParam.h"
 #include "AudioUtilities.h"
 #include "FloatConversion.h"
-#include "PannerNode.h"
 #include "ScriptExecutionContext.h"
 #include "WebKitAudioBufferSourceNode.h"
+#include "WebKitAudioPannerNode.h"
 #include <wtf/IsoMallocInlines.h>
 
 namespace WebCore {
@@ -538,8 +538,8 @@
 double AudioBufferSourceNode::totalPitchRate()
 {
     double dopplerRate = 1.0;
-    if (m_pannerNode)
-        dopplerRate = m_pannerNode->dopplerRate();
+    if (m_legacyPannerNode)
+        dopplerRate = m_legacyPannerNode->dopplerRate();
     
     // Incorporate buffer's sample-rate versus AudioContext's sample-rate.
     // Normally it's not an issue because buffers are loaded at the AudioContext's sample-rate, but we can handle it in any case.
@@ -567,21 +567,21 @@
     return !isPlayingOrScheduled() || hasFinished() || !m_buffer;
 }
 
-void AudioBufferSourceNode::setPannerNode(PannerNodeBase* pannerNode)
+void AudioBufferSourceNode::setPannerNode(WebKitAudioPannerNode* pannerNode)
 {
-    if (m_pannerNode != pannerNode && !hasFinished())
-        m_pannerNode = pannerNode;
+    if (m_legacyPannerNode != pannerNode && !hasFinished())
+        m_legacyPannerNode = pannerNode;
 }
 
 void AudioBufferSourceNode::clearPannerNode()
 {
-    m_pannerNode = nullptr;
+    m_legacyPannerNode = nullptr;
 }
 
 void AudioBufferSourceNode::finish()
 {
     clearPannerNode();
-    ASSERT(!m_pannerNode);
+    ASSERT(!m_legacyPannerNode);
     AudioScheduledSourceNode::finish();
 }
 

Modified: trunk/Source/WebCore/Modules/webaudio/AudioBufferSourceNode.h (274649 => 274650)


--- trunk/Source/WebCore/Modules/webaudio/AudioBufferSourceNode.h	2021-03-18 17:25:44 UTC (rev 274649)
+++ trunk/Source/WebCore/Modules/webaudio/AudioBufferSourceNode.h	2021-03-18 17:51:00 UTC (rev 274650)
@@ -33,7 +33,7 @@
 namespace WebCore {
 
 class AudioBuffer;
-class PannerNodeBase;
+class WebKitAudioPannerNode;
 struct AudioBufferSourceOptions;
 
 // AudioBufferSourceNode is an AudioNode representing an audio source from an in-memory audio asset represented by an AudioBuffer.
@@ -77,7 +77,7 @@
     AudioParam& playbackRate() { return m_playbackRate.get(); }
 
     // If a panner node is set, then we can incorporate doppler shift into the playback pitch rate.
-    void setPannerNode(PannerNodeBase*);
+    void setPannerNode(WebKitAudioPannerNode*);
     void clearPannerNode();
 
     // If we are no longer playing, propogate silence ahead to downstream nodes.
@@ -142,7 +142,7 @@
 
     // We optionally keep track of a panner node which has a doppler shift that is incorporated into
     // the pitch rate.
-    AudioConnectionRefPtr<PannerNodeBase> m_pannerNode;
+    AudioConnectionRefPtr<WebKitAudioPannerNode> m_legacyPannerNode;
 
     // This synchronizes process() with setBuffer() which can cause dynamic channel count changes.
     mutable Lock m_processLock;

Modified: trunk/Source/WebCore/Modules/webaudio/PannerNode.cpp (274649 => 274650)


--- trunk/Source/WebCore/Modules/webaudio/PannerNode.cpp	2021-03-18 17:25:44 UTC (rev 274649)
+++ trunk/Source/WebCore/Modules/webaudio/PannerNode.cpp	2021-03-18 17:51:00 UTC (rev 274650)
@@ -50,11 +50,6 @@
         x = 0.0;
 }
 
-PannerNodeBase::PannerNodeBase(BaseAudioContext& context)
-    : AudioNode(context, NodeTypePanner)
-{
-}
-
 ExceptionOr<Ref<PannerNode>> PannerNode::create(BaseAudioContext& context, const PannerOptions& options)
 {
     auto panner = adoptRef(*new PannerNode(context, options));
@@ -83,7 +78,7 @@
 }
 
 PannerNode::PannerNode(BaseAudioContext& context, const PannerOptions& options)
-    : PannerNodeBase(context)
+    : AudioNode(context, NodeTypePanner)
     , m_panningModel(options.panningModel)
     , m_positionX(AudioParam::create(context, "positionX"_s, options.positionX, -FLT_MAX, FLT_MAX, AutomationRate::ARate))
     , m_positionY(AudioParam::create(context, "positionY"_s, options.positionY, -FLT_MAX, FLT_MAX, AutomationRate::ARate))
@@ -109,21 +104,6 @@
     uninitialize();
 }
 
-void PannerNode::pullInputs(size_t framesToProcess)
-{
-    // We override pullInputs(), so we can detect new AudioSourceNodes which have connected to us when new connections are made.
-    // These AudioSourceNodes need to be made aware of our existence in order to handle doppler shift pitch changes.
-    if (m_connectionCount != context().connectionCount()) {
-        m_connectionCount = context().connectionCount();
-
-        // Recursively go through all nodes connected to us.
-        HashSet<AudioNode*> visitedNodes;
-        notifyAudioSourcesConnectedToNode(this, visitedNodes);
-    }
-    
-    AudioNode::pullInputs(framesToProcess);
-}
-
 void PannerNode::process(size_t framesToProcess)
 {
     AudioBus* destination = output(0)->bus();
@@ -533,11 +513,6 @@
     calculateAzimuthElevation(outAzimuth, outElevation, position(), listener().position(), listener().orientation(), listener().upVector());
 }
 
-float PannerNode::dopplerRate()
-{
-    return 1.0f;
-}
-
 bool PannerNode::requiresTailProcessing() const
 {
     // If there's no internal panner method set up yet, assume we require tail
@@ -564,35 +539,6 @@
     return calculateDistanceConeGain(position(), orientation(), listener().position());
 }
 
-void PannerNode::notifyAudioSourcesConnectedToNode(AudioNode* node, HashSet<AudioNode*>& visitedNodes)
-{
-    ASSERT(node);
-    if (!node)
-        return;
-        
-    // First check if this node is an AudioBufferSourceNode. If so, let it know about us so that doppler shift pitch can be taken into account.
-    if (node->nodeType() == NodeTypeAudioBufferSource) {
-        AudioBufferSourceNode* bufferSourceNode = reinterpret_cast<AudioBufferSourceNode*>(node);
-        bufferSourceNode->setPannerNode(this);
-    } else {    
-        // Go through all inputs to this node.
-        for (unsigned i = 0; i < node->numberOfInputs(); ++i) {
-            AudioNodeInput* input = node->input(i);
-
-            // For each input, go through all of its connections, looking for AudioBufferSourceNodes.
-            for (unsigned j = 0; j < input->numberOfRenderingConnections(); ++j) {
-                AudioNodeOutput* connectedOutput = input->renderingOutput(j);
-                AudioNode* connectedNode = connectedOutput->node();
-                if (visitedNodes.contains(connectedNode))
-                    continue;
-
-                visitedNodes.add(connectedNode);
-                notifyAudioSourcesConnectedToNode(connectedNode, visitedNodes);
-            }
-        }
-    }
-}
-
 } // namespace WebCore
 
 #endif // ENABLE(WEB_AUDIO)

Modified: trunk/Source/WebCore/Modules/webaudio/PannerNode.h (274649 => 274650)


--- trunk/Source/WebCore/Modules/webaudio/PannerNode.h	2021-03-18 17:25:44 UTC (rev 274649)
+++ trunk/Source/WebCore/Modules/webaudio/PannerNode.h	2021-03-18 17:51:00 UTC (rev 274650)
@@ -44,16 +44,6 @@
 class HRTFDatabaseLoader;
 class BaseAudioContext;
 
-class PannerNodeBase : public AudioNode {
-public:
-    virtual ~PannerNodeBase() = default;
-
-    virtual float dopplerRate() = 0;
-
-protected:
-    PannerNodeBase(BaseAudioContext&);
-};
-
 // PannerNode is an AudioNode with one input and one output.
 // It positions a sound in 3D space, with the exact effect dependent on the panning model.
 // It has a position and an orientation in 3D space which is relative to the position and orientation of the context's AudioListener.
@@ -61,7 +51,7 @@
 // A cone effect will attenuate the gain as the orientation moves away from the listener.
 // All of these effects follow the OpenAL specification very closely.
 
-class PannerNode final : public PannerNodeBase {
+class PannerNode final : public AudioNode {
     WTF_MAKE_ISO_ALLOCATED(PannerNode);
 public:
     static ExceptionOr<Ref<PannerNode>> create(BaseAudioContext&, const PannerOptions& = { });
@@ -71,7 +61,6 @@
     // AudioNode
     void process(size_t framesToProcess) override;
     void processOnlyAudioParams(size_t framesToProcess) final;
-    void pullInputs(size_t framesToProcess) override;
     void initialize() override;
     void uninitialize() override;
 
@@ -123,7 +112,6 @@
     ExceptionOr<void> setChannelCountMode(ChannelCountMode) final;
 
     void azimuthElevation(double* outAzimuth, double* outElevation);
-    float dopplerRate() final;
 
     double tailTime() const override { return m_panner ? m_panner->tailTime() : 0; }
     double latencyTime() const override { return m_panner ? m_panner->latencyTime() : 0; }
@@ -139,10 +127,6 @@
 
     bool requiresTailProcessing() const final;
 
-    // Notifies any AudioBufferSourceNodes connected to us either directly or indirectly about our existence.
-    // This is in order to handle the pitch change necessary for the doppler shift.
-    void notifyAudioSourcesConnectedToNode(AudioNode*, HashSet<AudioNode*>& visitedNodes);
-
     void processSampleAccurateValues(AudioBus* destination, const AudioBus* source, size_t framesToProcess);
     bool hasSampleAccurateValues() const;
     bool shouldUseARate() const;
@@ -165,8 +149,6 @@
     // HRTF Database loader
     RefPtr<HRTFDatabaseLoader> m_hrtfDatabaseLoader;
 
-    unsigned m_connectionCount { 0 };
-
     // Synchronize process() with setting of the panning model, source's location
     // information, listener, distance parameters and sound cones.
     mutable Lock m_processLock;

Modified: trunk/Source/WebCore/Modules/webaudio/WebKitAudioPannerNode.cpp (274649 => 274650)


--- trunk/Source/WebCore/Modules/webaudio/WebKitAudioPannerNode.cpp	2021-03-18 17:25:44 UTC (rev 274649)
+++ trunk/Source/WebCore/Modules/webaudio/WebKitAudioPannerNode.cpp	2021-03-18 17:51:00 UTC (rev 274650)
@@ -49,7 +49,7 @@
 }
 
 WebKitAudioPannerNode::WebKitAudioPannerNode(WebKitAudioContext& context)
-    : PannerNodeBase(context)
+    : AudioNode(context, NodeTypePanner)
 {
     initializeDefaultNodeOptions(2, ChannelCountMode::ClampedMax, ChannelInterpretation::Speakers);
 

Modified: trunk/Source/WebCore/Modules/webaudio/WebKitAudioPannerNode.h (274649 => 274650)


--- trunk/Source/WebCore/Modules/webaudio/WebKitAudioPannerNode.h	2021-03-18 17:25:44 UTC (rev 274649)
+++ trunk/Source/WebCore/Modules/webaudio/WebKitAudioPannerNode.h	2021-03-18 17:51:00 UTC (rev 274650)
@@ -32,7 +32,6 @@
 #include "Distance.h"
 #include "FloatPoint3D.h"
 #include "Panner.h"
-#include "PannerNode.h"
 #include "WebKitAudioContext.h"
 #include "WebKitAudioListener.h"
 #include <memory>
@@ -50,7 +49,7 @@
 // A cone effect will attenuate the gain as the orientation moves away from the listener.
 // All of these effects follow the OpenAL specification very closely.
 
-class WebKitAudioPannerNode final : public PannerNodeBase {
+class WebKitAudioPannerNode final : public AudioNode {
     WTF_MAKE_ISO_ALLOCATED(WebKitAudioPannerNode);
 public:
     static Ref<WebKitAudioPannerNode> create(WebKitAudioContext& context)
@@ -112,7 +111,7 @@
     void setConeOuterGain(double angle) { m_coneEffect.setOuterGain(angle); }
 
     void getAzimuthElevation(double* outAzimuth, double* outElevation);
-    float dopplerRate() final;
+    float dopplerRate();
 
     double tailTime() const override { return m_panner ? m_panner->tailTime() : 0; }
     double latencyTime() const override { return m_panner ? m_panner->latencyTime() : 0; }
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to