Bug 1048667. Small vsync framework. r=roc
authorMason Chang <mchang@mozilla.com>
Thu, 23 Oct 2014 18:50:31 -0700
changeset 236378 3a72e359110a92cada24fe8d4620433a7e3786f9
parent 236377 ae62fff56b88737a125857c89e62a9f3c50fa9bd
child 236379 efee5ba65af4e652d3371c9e9db29935d2ec642a
push id4311
push userraliiev@mozilla.com
push dateMon, 12 Jan 2015 19:37:41 +0000
treeherdermozilla-beta@150c9fed433b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs1048667
milestone36.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 1048667. Small vsync framework. r=roc
gfx/layers/ipc/CompositorParent.h
widget/VsyncDispatcher.cpp
widget/VsyncDispatcher.h
widget/gonk/HwcComposer2D.cpp
widget/gonk/moz.build
--- a/gfx/layers/ipc/CompositorParent.h
+++ b/gfx/layers/ipc/CompositorParent.h
@@ -92,17 +92,16 @@ private:
 /**
  * Manages the vsync (de)registration and tracking on behalf of the
  * compositor when it need to paint.
  * Turns vsync notifications into scheduled composites.
  **/
 
 class CompositorVsyncObserver MOZ_FINAL : public VsyncObserver
 {
-  NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION(CompositorVsyncObserver)
   friend class CompositorParent;
 
 public:
   CompositorVsyncObserver(CompositorParent* aCompositorParent);
   virtual bool NotifyVsync(TimeStamp aVsyncTimestamp) MOZ_OVERRIDE;
   void SetNeedsComposite(bool aSchedule);
   bool NeedsComposite();
   void CancelCurrentCompositeTask();
--- a/widget/VsyncDispatcher.cpp
+++ b/widget/VsyncDispatcher.cpp
@@ -1,16 +1,21 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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/. */
 
 #include "VsyncDispatcher.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "CompositorParent.h"
+#include "gfxPrefs.h"
+
+#ifdef MOZ_WIDGET_GONK
+#include "GeckoTouchDispatcher.h"
+#endif
 
 using namespace mozilla::layers;
 
 namespace mozilla {
 
 StaticRefPtr<VsyncDispatcher> sVsyncDispatcher;
 
 /*static*/ VsyncDispatcher*
@@ -20,29 +25,76 @@ VsyncDispatcher::GetInstance()
     sVsyncDispatcher = new VsyncDispatcher();
     ClearOnShutdown(&sVsyncDispatcher);
   }
 
   return sVsyncDispatcher;
 }
 
 VsyncDispatcher::VsyncDispatcher()
+  : mCompositorObserverLock("CompositorObserverLock")
 {
 
 }
 
 VsyncDispatcher::~VsyncDispatcher()
 {
+  MutexAutoLock lock(mCompositorObserverLock);
+  mCompositorObservers.Clear();
+}
+
+void
+VsyncDispatcher::DispatchTouchEvents(bool aNotifiedCompositors, nsecs_t aAndroidVsyncTime)
+{
+  // Touch events can sometimes start a composite, so make sure we dispatch touches
+  // even if we don't composite
+#ifdef MOZ_WIDGET_GONK
+  if (!aNotifiedCompositors && gfxPrefs::TouchResampling()) {
+    GeckoTouchDispatcher::NotifyVsync(aAndroidVsyncTime);
+  }
+#endif
+}
+
+void
+VsyncDispatcher::NotifyVsync(TimeStamp aVsyncTimestamp, nsecs_t aAndroidVsyncTime)
+{
+  bool notifiedCompositors = false;
+  if (gfxPrefs::VsyncAlignedCompositor()) {
+    MutexAutoLock lock(mCompositorObserverLock);
+    notifiedCompositors = NotifyVsyncObservers(aVsyncTimestamp, mCompositorObservers);
+  }
+
+  DispatchTouchEvents(notifiedCompositors, aAndroidVsyncTime);
+}
+
+bool
+VsyncDispatcher::NotifyVsyncObservers(TimeStamp aVsyncTimestamp, nsTArray<nsRefPtr<VsyncObserver>>& aObservers)
+{
+  // Callers should lock the respective lock for the aObservers before calling this function
+  for (size_t i = 0; i < aObservers.Length(); i++) {
+    aObservers[i]->NotifyVsync(aVsyncTimestamp);
+ }
+ return aObservers.IsEmpty();
 }
 
 void
 VsyncDispatcher::AddCompositorVsyncObserver(VsyncObserver* aVsyncObserver)
 {
   MOZ_ASSERT(CompositorParent::IsInCompositorThread());
+  MutexAutoLock lock(mCompositorObserverLock);
+  if (!mCompositorObservers.Contains(aVsyncObserver)) {
+    mCompositorObservers.AppendElement(aVsyncObserver);
+  }
 }
 
 void
 VsyncDispatcher::RemoveCompositorVsyncObserver(VsyncObserver* aVsyncObserver)
 {
   MOZ_ASSERT(CompositorParent::IsInCompositorThread());
+  MutexAutoLock lock(mCompositorObserverLock);
+  if (mCompositorObservers.Contains(aVsyncObserver)) {
+    mCompositorObservers.RemoveElement(aVsyncObserver);
+  } else {
+    NS_WARNING("Could not delete a compositor vsync observer\n");
+  }
 }
 
 } // namespace mozilla
--- a/widget/VsyncDispatcher.h
+++ b/widget/VsyncDispatcher.h
@@ -1,44 +1,70 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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_widget_VsyncDispatcher_h
 #define mozilla_widget_VsyncDispatcher_h
 
+#include "base/message_loop.h"
+#include "mozilla/Mutex.h"
 #include "nsISupportsImpl.h"
+#include "nsTArray.h"
+#include "ThreadSafeRefcountingWithMainThreadDestruction.h"
+
+typedef int64_t nsecs_t; // nano-seconds
+
+class MessageLoop;
 
 namespace mozilla {
 class TimeStamp;
 
+namespace layers {
+class CompositorVsyncObserver;
+}
+
 class VsyncObserver
 {
+  // Must be destroyed on main thread since the compositor is as well
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION(VsyncObserver)
+
 public:
   // The method called when a vsync occurs. Return true if some work was done.
   // Vsync notifications will occur on the hardware vsync thread
   virtual bool NotifyVsync(TimeStamp aVsyncTimestamp) = 0;
 
 protected:
-  virtual ~VsyncObserver() { }
+  VsyncObserver() {}
+  virtual ~VsyncObserver() {}
 };
 
 // VsyncDispatcher is used to dispatch vsync events to the registered observers.
 class VsyncDispatcher
 {
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VsyncDispatcher)
 
 public:
   static VsyncDispatcher* GetInstance();
+  // Called on the vsync thread when a hardware vsync occurs
+  void NotifyVsync(TimeStamp aVsyncTimestamp, nsecs_t aAndroidVsyncTime);
 
   // Compositor vsync observers must be added/removed on the compositor thread
   void AddCompositorVsyncObserver(VsyncObserver* aVsyncObserver);
   void RemoveCompositorVsyncObserver(VsyncObserver* aVsyncObserver);
 
 private:
   VsyncDispatcher();
   virtual ~VsyncDispatcher();
+  void DispatchTouchEvents(bool aNotifiedCompositors, nsecs_t aAndroidVSyncTime);
+
+  // Called on the vsync thread. Returns true if observers were notified
+  bool NotifyVsyncObservers(TimeStamp aVsyncTimestamp, nsTArray<nsRefPtr<VsyncObserver>>& aObservers);
+
+  // Can have multiple compositors. On desktop, this is 1 compositor per window
+  Mutex mCompositorObserverLock;
+  nsTArray<nsRefPtr<VsyncObserver>> mCompositorObservers;
 };
 
 } // namespace mozilla
 
 #endif // __mozilla_widget_VsyncDispatcher_h
--- a/widget/gonk/HwcComposer2D.cpp
+++ b/widget/gonk/HwcComposer2D.cpp
@@ -235,25 +235,26 @@ HwcComposer2D::RunVsyncEventControl(bool
             device->eventControl(device, HWC_DISPLAY_PRIMARY, HWC_EVENT_VSYNC, aEnable);
         }
     }
 }
 
 void
 HwcComposer2D::Vsync(int aDisplay, nsecs_t aVsyncTimestamp)
 {
+    nsecs_t timeSinceInit = aVsyncTimestamp - sAndroidInitTime;
+    TimeStamp vsyncTime = sMozInitTime + TimeDuration::FromMicroseconds(timeSinceInit / 1000);
+
 #ifdef MOZ_ENABLE_PROFILER_SPS
     if (profiler_is_active()) {
-      nsecs_t timeSinceInit = aVsyncTimestamp - sAndroidInitTime;
-      TimeStamp vsyncTime = sMozInitTime + TimeDuration::FromMicroseconds(timeSinceInit / 1000);
-      CompositorParent::PostInsertVsyncProfilerMarker(vsyncTime);
+        CompositorParent::PostInsertVsyncProfilerMarker(vsyncTime);
     }
 #endif
 
-    GeckoTouchDispatcher::NotifyVsync(aVsyncTimestamp);
+    VsyncDispatcher::GetInstance()->NotifyVsync(vsyncTime, aVsyncTimestamp);
 }
 
 // Called on the "invalidator" thread (run from HAL).
 void
 HwcComposer2D::Invalidate()
 {
     if (!Initialized()) {
         LOGE("HwcComposer2D::Invalidate failed!");
--- a/widget/gonk/moz.build
+++ b/widget/gonk/moz.build
@@ -10,16 +10,17 @@
 #
 # Unless required by applicable law or agreed to in writing, software
 # distributed under the License is distributed on an "AS IS" BASIS,
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
 EXPORTS += [
+    'GeckoTouchDispatcher.h',
     'GonkPermission.h',
     'OrientationObserver.h',
 ]
 
 DIRS += ['libdisplay', 'nativewindow']
 
 # libui files
 SOURCES += ['libui/' + src for src in [