Bug 1173016 - Cache the basic waveform PeriodicWaves. r=karlt
authorPaul Adenot <paul@paul.cx>
Mon, 15 Jun 2015 18:16:16 +0200
changeset 251483 146b55675c93adf46164f124b2fb8012ab44e2a1
parent 251482 2df2e0c0a7b4dc6acb8f4d604fb82840119cbbf9
child 251484 911c598a9ef2c82458c67fc43da0512ce9064114
push id29001
push userkwierso@gmail.com
push dateTue, 07 Jul 2015 00:07:21 +0000
treeherdermozilla-central@e8e7191442b3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskarlt
bugs1173016
milestone42.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1173016 - Cache the basic waveform PeriodicWaves. r=karlt
dom/media/webaudio/AudioContext.cpp
dom/media/webaudio/AudioContext.h
dom/media/webaudio/OscillatorNode.cpp
dom/media/webaudio/PeriodicWave.h
dom/media/webaudio/blink/PeriodicWave.h
--- a/dom/media/webaudio/AudioContext.cpp
+++ b/dom/media/webaudio/AudioContext.cpp
@@ -30,16 +30,17 @@
 #include "StereoPannerNode.h"
 #include "ChannelMergerNode.h"
 #include "ChannelSplitterNode.h"
 #include "MediaStreamAudioDestinationNode.h"
 #include "WaveShaperNode.h"
 #include "PeriodicWave.h"
 #include "ConvolverNode.h"
 #include "OscillatorNode.h"
+#include "blink/PeriodicWave.h"
 #include "nsNetUtil.h"
 #include "AudioStream.h"
 #include "mozilla/dom/Promise.h"
 
 namespace mozilla {
 namespace dom {
 
 // 0 is a special value that MediaStreams use to denote they are not part of a
@@ -1045,10 +1046,53 @@ AudioContext::CollectReports(nsIHandleRe
 }
 
 double
 AudioContext::ExtraCurrentTime() const
 {
   return mDestination->ExtraCurrentTime();
 }
 
+BasicWaveFormCache*
+AudioContext::GetBasicWaveFormCache()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  if (!mBasicWaveFormCache) {
+    mBasicWaveFormCache = new BasicWaveFormCache(SampleRate());
+  }
+  return mBasicWaveFormCache;
+}
+
+BasicWaveFormCache::BasicWaveFormCache(uint32_t aSampleRate)
+  : mSampleRate(aSampleRate)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+}
+BasicWaveFormCache::~BasicWaveFormCache()
+{ }
+
+WebCore::PeriodicWave*
+BasicWaveFormCache::GetBasicWaveForm(OscillatorType aType)
+{
+  MOZ_ASSERT(!NS_IsMainThread());
+  if (aType == OscillatorType::Sawtooth) {
+    if (!mSawtooth) {
+      mSawtooth = WebCore::PeriodicWave::createSawtooth(mSampleRate);
+    }
+    return mSawtooth;
+  } else if (aType == OscillatorType::Square) {
+    if (!mSquare) {
+      mSquare = WebCore::PeriodicWave::createSquare(mSampleRate);
+    }
+    return mSquare;
+  } else if (aType == OscillatorType::Triangle) {
+    if (!mTriangle) {
+      mTriangle = WebCore::PeriodicWave::createTriangle(mSampleRate);
+    }
+    return mTriangle;
+  } else {
+    MOZ_ASSERT(false, "Not reached");
+    return nullptr;
+  }
+}
+
 }
 }
--- a/dom/media/webaudio/AudioContext.h
+++ b/dom/media/webaudio/AudioContext.h
@@ -22,16 +22,20 @@
 #include "nsIMemoryReporter.h"
 
 // X11 has a #define for CurrentTime. Unbelievable :-(.
 // See dom/media/DOMMediaStream.h for more fun!
 #ifdef CurrentTime
 #undef CurrentTime
 #endif
 
+namespace WebCore {
+  class PeriodicWave;
+};
+
 class nsPIDOMWindow;
 
 namespace mozilla {
 
 class DOMMediaStream;
 class ErrorResult;
 class MediaStream;
 class MediaStreamGraph;
@@ -60,16 +64,35 @@ class MediaStreamAudioDestinationNode;
 class MediaStreamAudioSourceNode;
 class OscillatorNode;
 class PannerNode;
 class ScriptProcessorNode;
 class StereoPannerNode;
 class WaveShaperNode;
 class PeriodicWave;
 class Promise;
+enum class OscillatorType : uint32_t;
+
+// This is addrefed by the OscillatorNodeEngine on the main thread
+// and then used from the MSG thread.
+// It can be released either from the graph thread or the main thread.
+class BasicWaveFormCache
+{
+public:
+  BasicWaveFormCache(uint32_t aSampleRate);
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(BasicWaveFormCache)
+  WebCore::PeriodicWave* GetBasicWaveForm(OscillatorType aType);
+private:
+  ~BasicWaveFormCache();
+  nsRefPtr<WebCore::PeriodicWave> mSawtooth;
+  nsRefPtr<WebCore::PeriodicWave> mSquare;
+  nsRefPtr<WebCore::PeriodicWave> mTriangle;
+  uint32_t mSampleRate;
+};
+
 
 /* This runnable allows the MSG to notify the main thread when audio is actually
  * flowing */
 class StateChangeTask final : public nsRunnable
 {
 public:
   /* This constructor should be used when this event is sent from the main
    * thread. */
@@ -289,16 +312,18 @@ public:
 
   double StreamTimeToDOMTime(double aTime) const
   {
     return aTime + ExtraCurrentTime();
   }
 
   void OnStateChanged(void* aPromise, AudioContextState aNewState);
 
+  BasicWaveFormCache* GetBasicWaveFormCache();
+
   IMPL_EVENT_HANDLER(mozinterruptbegin)
   IMPL_EVENT_HANDLER(mozinterruptend)
 
 private:
   /**
    * Returns the amount of extra time added to the current time of the
    * AudioDestinationNode's MediaStream to get this AudioContext's currentTime.
    * Must be subtracted from all DOM API parameter times that are on the same
@@ -334,16 +359,18 @@ private:
   // they are resolved, so we can safely pass them accross threads.
   nsTArray<nsRefPtr<Promise>> mPromiseGripArray;
   // See RegisterActiveNode.  These will keep the AudioContext alive while it
   // is rendering and the window remains alive.
   nsTHashtable<nsRefPtrHashKey<AudioNode> > mActiveNodes;
   // Hashsets containing all the PannerNodes, to compute the doppler shift.
   // These are weak pointers.
   nsTHashtable<nsPtrHashKey<PannerNode> > mPannerNodes;
+  // Cache to avoid recomputing basic waveforms all the time.
+  nsRefPtr<BasicWaveFormCache> mBasicWaveFormCache;
   // Number of channels passed in the OfflineAudioContext ctor.
   uint32_t mNumberOfChannels;
   // Number of nodes that currently exist for this AudioContext
   int32_t mNodeCount;
   bool mIsOffline;
   bool mIsStarted;
   bool mIsShutDown;
   // Close has been called, reject suspend and resume call.
--- a/dom/media/webaudio/OscillatorNode.cpp
+++ b/dom/media/webaudio/OscillatorNode.cpp
@@ -35,16 +35,18 @@ public:
     // Keep the default values in sync with OscillatorNode::OscillatorNode.
     , mFrequency(440.f)
     , mDetune(0.f)
     , mType(OscillatorType::Sine)
     , mPhase(0.)
     , mRecomputeParameters(true)
     , mCustomLength(0)
   {
+    MOZ_ASSERT(NS_IsMainThread());
+    mBasicWaveFormCache = aDestination->Context()->GetBasicWaveFormCache();
   }
 
   void SetSourceStream(AudioNodeStream* aSource)
   {
     mSource = aSource;
   }
 
   enum Parameters {
@@ -99,23 +101,19 @@ public:
           mPeriodicWave = nullptr;
           mRecomputeParameters = true;
         }
         switch (mType) {
           case OscillatorType::Sine:
             mPhase = 0.0;
             break;
           case OscillatorType::Square:
-            mPeriodicWave = WebCore::PeriodicWave::createSquare(mSource->SampleRate());
-            break;
           case OscillatorType::Triangle:
-            mPeriodicWave = WebCore::PeriodicWave::createTriangle(mSource->SampleRate());
-            break;
           case OscillatorType::Sawtooth:
-            mPeriodicWave = WebCore::PeriodicWave::createSawtooth(mSource->SampleRate());
+            mPeriodicWave = mBasicWaveFormCache->GetBasicWaveForm(mType);
             break;
           case OscillatorType::Custom:
             break;
           default:
             NS_ERROR("Bad OscillatorNodeEngine type parameter.");
         }
         // End type switch.
         break;
@@ -366,18 +364,19 @@ public:
   AudioParamTimeline mFrequency;
   AudioParamTimeline mDetune;
   OscillatorType mType;
   float mPhase;
   float mFinalFrequency;
   float mPhaseIncrement;
   bool mRecomputeParameters;
   nsRefPtr<ThreadSharedFloatArrayBufferList> mCustom;
+  nsRefPtr<BasicWaveFormCache> mBasicWaveFormCache;
   uint32_t mCustomLength;
-  nsAutoPtr<WebCore::PeriodicWave> mPeriodicWave;
+  nsRefPtr<WebCore::PeriodicWave> mPeriodicWave;
 };
 
 OscillatorNode::OscillatorNode(AudioContext* aContext)
   : AudioNode(aContext,
               2,
               ChannelCountMode::Max,
               ChannelInterpretation::Speakers)
   , mType(OscillatorType::Sine)
--- a/dom/media/webaudio/PeriodicWave.h
+++ b/dom/media/webaudio/PeriodicWave.h
@@ -7,17 +7,16 @@
 #ifndef PeriodicWave_h_
 #define PeriodicWave_h_
 
 #include "nsWrapperCache.h"
 #include "nsCycleCollectionParticipant.h"
 #include "mozilla/Attributes.h"
 #include "AudioContext.h"
 #include "AudioNodeEngine.h"
-#include "nsAutoPtr.h"
 
 namespace mozilla {
 
 namespace dom {
 
 class PeriodicWave final : public nsWrapperCache
 {
 public:
--- a/dom/media/webaudio/blink/PeriodicWave.h
+++ b/dom/media/webaudio/blink/PeriodicWave.h
@@ -37,16 +37,19 @@
 
 namespace WebCore {
 
 typedef AlignedTArray<float> AlignedAudioFloatArray;
 typedef nsTArray<float> AudioFloatArray;
 
 class PeriodicWave {
 public:
+
+    NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PeriodicWave);
+
     static PeriodicWave* createSine(float sampleRate);
     static PeriodicWave* createSquare(float sampleRate);
     static PeriodicWave* createSawtooth(float sampleRate);
     static PeriodicWave* createTriangle(float sampleRate);
 
     // Creates an arbitrary periodic wave given the frequency components
     // (Fourier coefficients).
     static PeriodicWave* create(float sampleRate,
@@ -70,16 +73,17 @@ public:
 
     unsigned periodicWaveSize() const { return m_periodicWaveSize; }
     float sampleRate() const { return m_sampleRate; }
 
     size_t sizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
 
 private:
     explicit PeriodicWave(float sampleRate);
+    ~PeriodicWave() {}
 
     void generateBasicWaveform(mozilla::dom::OscillatorType);
 
     float m_sampleRate;
     unsigned m_periodicWaveSize;
     unsigned m_numberOfRanges;
     float m_centsPerRange;