Bug 1451469 - Implement the guts of the WR sampler thread registration. r=botond
authorKartikaya Gupta <kgupta@mozilla.com>
Mon, 16 Apr 2018 17:39:14 -0400
changeset 467785 baf94bbd3243d3cea9f6d6e205d39a858c80f145
parent 467784 78d008b79f626754c6d9bc99aa560ea6bf6ee5cb
child 467786 32bcab2ef2e524ff64c35ebf1879332507720c31
push id9165
push userasasaki@mozilla.com
push dateThu, 26 Apr 2018 21:04:54 +0000
treeherdermozilla-beta@064c3804de2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbotond
bugs1451469
milestone61.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 1451469 - Implement the guts of the WR sampler thread registration. r=botond This lets the APZSampler know which thread is the actual sampler thread. This is only really used for the thread assertions, but might be useful for debugging and such as well. Note that since this behaviour is not dependent on any prefs (unlike the updater thread, which is only the scene builder thread when the async scene building pref is enabled), we don't hook it up to the rust code just yet; that will happen in the last patch. MozReview-Commit-ID: DrrJOyFA65D
gfx/layers/apz/public/APZSampler.h
gfx/layers/apz/src/APZSampler.cpp
--- a/gfx/layers/apz/public/APZSampler.h
+++ b/gfx/layers/apz/public/APZSampler.h
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_layers_APZSampler_h
 #define mozilla_layers_APZSampler_h
 
 #include <unordered_map>
 
+#include "base/platform_thread.h" // for PlatformThreadId
 #include "mozilla/layers/AsyncCompositionManager.h" // for AsyncTransform
 #include "mozilla/StaticMutex.h"
 #include "nsTArray.h"
 #include "Units.h"
 
 namespace mozilla {
 
 class TimeStamp;
@@ -38,16 +39,24 @@ struct ScrollbarData;
 class APZSampler {
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(APZSampler)
 
 public:
   explicit APZSampler(const RefPtr<APZCTreeManager>& aApz);
 
   void SetWebRenderWindowId(const wr::WindowId& aWindowId);
 
+  /**
+   * This function is invoked from rust on the render backend thread when it
+   * is created. It effectively tells the APZSampler "the current thread is
+   * the sampler thread for this window id" and allows APZSampler to remember
+   * which thread it is.
+   */
+  static void SetSamplerThread(const wr::WrWindowId& aWindowId);
+
   bool PushStateToWR(wr::TransactionBuilder& aTxn,
                      const TimeStamp& aSampleTime);
 
   bool SampleAnimations(const LayerMetricsWrapper& aLayer,
                         const TimeStamp& aSampleTime);
 
   /**
    * Compute the updated shadow transform for a scroll thumb layer that
@@ -85,26 +94,40 @@ public:
   /**
    * Returns true if currently on the APZSampler's "sampler thread".
    */
   bool IsSamplerThread() const;
 
 protected:
   virtual ~APZSampler();
 
+  bool UsingWebRenderSamplerThread() const;
   static already_AddRefed<APZSampler> GetSampler(const wr::WrWindowId& aWindowId);
 
 private:
   RefPtr<APZCTreeManager> mApz;
 
   // Used to manage the mapping from a WR window id to APZSampler. These are only
   // used if WebRender is enabled. Both sWindowIdMap and mWindowId should only
   // be used while holding the sWindowIdLock.
   static StaticMutex sWindowIdLock;
   static std::unordered_map<uint64_t, APZSampler*> sWindowIdMap;
   Maybe<wr::WrWindowId> mWindowId;
 
+  // If WebRender is enabled, this holds the thread id of the render backend
+  // thread (which is the sampler thread) for the compositor associated with
+  // this APZSampler instance.
+  // This is written to once during init and never cleared, and so reading it
+  // from multiple threads during normal operation (after initialization)
+  // without locking should be fine.
+  Maybe<PlatformThreadId> mSamplerThreadId;
+#ifdef DEBUG
+  // This flag is used to ensure that we don't ever try to do sampler-thread
+  // stuff before the updater thread has been properly initialized.
+  mutable bool mSamplerThreadQueried;
+#endif
+
 };
 
 } // namespace layers
 } // namespace mozilla
 
 #endif // mozilla_layers_APZSampler_h
--- a/gfx/layers/apz/src/APZSampler.cpp
+++ b/gfx/layers/apz/src/APZSampler.cpp
@@ -18,16 +18,19 @@ namespace mozilla {
 namespace layers {
 
 StaticMutex APZSampler::sWindowIdLock;
 std::unordered_map<uint64_t, APZSampler*> APZSampler::sWindowIdMap;
 
 
 APZSampler::APZSampler(const RefPtr<APZCTreeManager>& aApz)
   : mApz(aApz)
+#ifdef DEBUG
+  , mSamplerThreadQueried(false)
+#endif
 {
   MOZ_ASSERT(aApz);
   mApz->SetSampler(this);
 }
 
 APZSampler::~APZSampler()
 {
   mApz->SetSampler(nullptr);
@@ -42,16 +45,26 @@ void
 APZSampler::SetWebRenderWindowId(const wr::WindowId& aWindowId)
 {
   StaticMutexAutoLock lock(sWindowIdLock);
   MOZ_ASSERT(!mWindowId);
   mWindowId = Some(aWindowId);
   sWindowIdMap[wr::AsUint64(aWindowId)] = this;
 }
 
+/*static*/ void
+APZSampler::SetSamplerThread(const wr::WrWindowId& aWindowId)
+{
+  if (RefPtr<APZSampler> sampler = GetSampler(aWindowId)) {
+    // Ensure nobody tried to use the updater thread before this point.
+    MOZ_ASSERT(!sampler->mSamplerThreadQueried);
+    sampler->mSamplerThreadId = Some(PlatformThread::CurrentId());
+  }
+}
+
 bool
 APZSampler::PushStateToWR(wr::TransactionBuilder& aTxn,
                           const TimeStamp& aSampleTime)
 {
   // This function will be removed eventually since we'll have WR pull
   // the transforms from APZ instead.
   return mApz->PushStateToWR(aTxn, aSampleTime);
 }
@@ -168,19 +181,39 @@ APZSampler::AssertOnSamplerThread() cons
   if (APZThreadUtils::GetThreadAssertionsEnabled()) {
     MOZ_ASSERT(IsSamplerThread());
   }
 }
 
 bool
 APZSampler::IsSamplerThread() const
 {
+  if (UsingWebRenderSamplerThread()) {
+    return PlatformThread::CurrentId() == *mSamplerThreadId;
+  }
   return CompositorThreadHolder::IsInCompositorThread();
 }
 
+bool
+APZSampler::UsingWebRenderSamplerThread() const
+{
+  // If mSamplerThreadId is not set at the point that this is called, then
+  // that means that either (a) WebRender is not enabled for the compositor
+  // to which this APZSampler is attached or (b) we are attempting to do
+  // something sampler-related before WebRender is up and running. In case
+  // (a) falling back to the compositor thread is correct, and in case (b)
+  // we should stop doing the sampler-related thing so early. We catch this
+  // case by setting the mSamplerThreadQueried flag and asserting on WR
+  // initialization.
+#ifdef DEBUG
+  mSamplerThreadQueried = true;
+#endif
+  return mSamplerThreadId.isSome();
+}
+
 /*static*/ already_AddRefed<APZSampler>
 APZSampler::GetSampler(const wr::WrWindowId& aWindowId)
 {
   RefPtr<APZSampler> sampler;
   StaticMutexAutoLock lock(sWindowIdLock);
   auto it = sWindowIdMap.find(wr::AsUint64(aWindowId));
   if (it != sWindowIdMap.end()) {
     sampler = it->second;