Bug 1121331 - Part1: PVsync protocol for vsync event passing. r=bent
authorJerryShih <hshih@mozilla.com>
Wed, 14 Jan 2015 00:37:00 +0100
changeset 223935 b9cd3847b0afc227c4071d11a9a2cc8688b9bde8
parent 223934 61c681281c3047a9f7acf1aba6d9270a4dc1d48a
child 223936 11e3a259b15d83f4b2ac390b33f71fc156cccccf
push id54084
push usercbook@mozilla.com
push dateThu, 15 Jan 2015 10:47:30 +0000
treeherdermozilla-inbound@828b434f69f7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbent
bugs1121331
milestone38.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 1121331 - Part1: PVsync protocol for vsync event passing. r=bent
ipc/glue/BackgroundChildImpl.cpp
ipc/glue/BackgroundChildImpl.h
ipc/glue/BackgroundParentImpl.cpp
ipc/glue/BackgroundParentImpl.h
ipc/glue/PBackground.ipdl
layout/ipc/PVsync.ipdl
layout/ipc/VsyncChild.cpp
layout/ipc/VsyncChild.h
layout/ipc/VsyncParent.cpp
layout/ipc/VsyncParent.h
layout/ipc/moz.build
--- a/ipc/glue/BackgroundChildImpl.cpp
+++ b/ipc/glue/BackgroundChildImpl.cpp
@@ -6,16 +6,17 @@
 
 #include "ActorsChild.h" // IndexedDB
 #include "FileDescriptorSetChild.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/dom/PBlobChild.h"
 #include "mozilla/dom/indexedDB/PBackgroundIDBFactoryChild.h"
 #include "mozilla/dom/ipc/BlobChild.h"
 #include "mozilla/ipc/PBackgroundTestChild.h"
+#include "mozilla/layout/VsyncChild.h"
 #include "nsID.h"
 #include "nsTraceRefcnt.h"
 
 namespace {
 
 class TestChild MOZ_FINAL : public mozilla::ipc::PBackgroundTestChild
 {
   friend class mozilla::ipc::BackgroundChildImpl;
@@ -180,16 +181,31 @@ BackgroundChildImpl::DeallocPFileDescrip
                                                 PFileDescriptorSetChild* aActor)
 {
   MOZ_ASSERT(aActor);
 
   delete static_cast<FileDescriptorSetChild*>(aActor);
   return true;
 }
 
+BackgroundChildImpl::PVsyncChild*
+BackgroundChildImpl::AllocPVsyncChild()
+{
+  return new mozilla::layout::VsyncChild();
+}
+
+bool
+BackgroundChildImpl::DeallocPVsyncChild(PVsyncChild* aActor)
+{
+  MOZ_ASSERT(aActor);
+
+  delete static_cast<mozilla::layout::VsyncChild*>(aActor);
+  return true;
+}
+
 } // namespace ipc
 } // namespace mozilla
 
 bool
 TestChild::Recv__delete__(const nsCString& aTestArg)
 {
   MOZ_RELEASE_ASSERT(aTestArg == mTestArg,
                      "BackgroundTest message was corrupted!");
--- a/ipc/glue/BackgroundChildImpl.h
+++ b/ipc/glue/BackgroundChildImpl.h
@@ -65,16 +65,22 @@ protected:
   DeallocPBlobChild(PBlobChild* aActor) MOZ_OVERRIDE;
 
   virtual PFileDescriptorSetChild*
   AllocPFileDescriptorSetChild(const FileDescriptor& aFileDescriptor)
                                MOZ_OVERRIDE;
 
   virtual bool
   DeallocPFileDescriptorSetChild(PFileDescriptorSetChild* aActor) MOZ_OVERRIDE;
+
+  virtual PVsyncChild*
+  AllocPVsyncChild() MOZ_OVERRIDE;
+
+  virtual bool
+  DeallocPVsyncChild(PVsyncChild* aActor) MOZ_OVERRIDE;
 };
 
 class BackgroundChildImpl::ThreadLocal MOZ_FINAL
 {
   friend class nsAutoPtr<ThreadLocal>;
 
 public:
   nsAutoPtr<mozilla::dom::indexedDB::ThreadLocal> mIndexedDBThreadLocal;
--- a/ipc/glue/BackgroundParentImpl.cpp
+++ b/ipc/glue/BackgroundParentImpl.cpp
@@ -6,16 +6,18 @@
 
 #include "FileDescriptorSetParent.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/dom/PBlobParent.h"
 #include "mozilla/dom/indexedDB/ActorsParent.h"
 #include "mozilla/dom/ipc/BlobParent.h"
 #include "mozilla/ipc/BackgroundParent.h"
 #include "mozilla/ipc/PBackgroundTestParent.h"
+#include "mozilla/layout/VsyncParent.h"
+#include "nsRefPtr.h"
 #include "nsThreadUtils.h"
 #include "nsTraceRefcnt.h"
 #include "nsXULAppAPI.h"
 
 #ifdef DISABLE_ASSERTS_FOR_FUZZING
 #define ASSERT_UNLESS_FUZZING(...) do { } while (0)
 #else
 #define ASSERT_UNLESS_FUZZING(...) MOZ_ASSERT(false)
@@ -202,16 +204,42 @@ BackgroundParentImpl::DeallocPFileDescri
   AssertIsInMainProcess();
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(aActor);
 
   delete static_cast<FileDescriptorSetParent*>(aActor);
   return true;
 }
 
+BackgroundParentImpl::PVsyncParent*
+BackgroundParentImpl::AllocPVsyncParent()
+{
+  AssertIsInMainProcess();
+  AssertIsOnBackgroundThread();
+
+  nsRefPtr<mozilla::layout::VsyncParent> actor =
+      mozilla::layout::VsyncParent::Create();
+  // There still has one ref-count after return, and it will be released in
+  // DeallocPVsyncParent().
+  return actor.forget().take();
+}
+
+bool
+BackgroundParentImpl::DeallocPVsyncParent(PVsyncParent* aActor)
+{
+  AssertIsInMainProcess();
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(aActor);
+
+  // This actor already has one ref-count. Please check AllocPVsyncParent().
+  nsRefPtr<mozilla::layout::VsyncParent> actor =
+      dont_AddRef(static_cast<mozilla::layout::VsyncParent*>(aActor));
+  return true;
+}
+
 } // namespace ipc
 } // namespace mozilla
 
 void
 TestParent::ActorDestroy(ActorDestroyReason aWhy)
 {
   AssertIsInMainProcess();
   AssertIsOnBackgroundThread();
--- a/ipc/glue/BackgroundParentImpl.h
+++ b/ipc/glue/BackgroundParentImpl.h
@@ -4,16 +4,21 @@
 
 #ifndef mozilla_ipc_backgroundparentimpl_h__
 #define mozilla_ipc_backgroundparentimpl_h__
 
 #include "mozilla/Attributes.h"
 #include "mozilla/ipc/PBackgroundParent.h"
 
 namespace mozilla {
+
+namespace layout {
+class VsyncParent;
+}
+
 namespace ipc {
 
 // Instances of this class should never be created directly. This class is meant
 // to be inherited in BackgroundImpl.
 class BackgroundParentImpl : public PBackgroundParent
 {
 protected:
   BackgroundParentImpl();
@@ -53,14 +58,20 @@ protected:
 
   virtual PFileDescriptorSetParent*
   AllocPFileDescriptorSetParent(const FileDescriptor& aFileDescriptor)
                                 MOZ_OVERRIDE;
 
   virtual bool
   DeallocPFileDescriptorSetParent(PFileDescriptorSetParent* aActor)
                                   MOZ_OVERRIDE;
+
+  virtual PVsyncParent*
+  AllocPVsyncParent() MOZ_OVERRIDE;
+
+  virtual bool
+  DeallocPVsyncParent(PVsyncParent* aActor) MOZ_OVERRIDE;
 };
 
 } // namespace ipc
 } // namespace mozilla
 
 #endif // mozilla_ipc_backgroundparentimpl_h__
--- a/ipc/glue/PBackground.ipdl
+++ b/ipc/glue/PBackground.ipdl
@@ -1,36 +1,40 @@
 /* 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 protocol PBackgroundIDBFactory;
 include protocol PBackgroundTest;
 include protocol PBlob;
 include protocol PFileDescriptorSet;
+include protocol PVsync;
 
 include DOMTypes;
 include PBackgroundIDBSharedTypes;
 
 namespace mozilla {
 namespace ipc {
 
 sync protocol PBackground
 {
   manages PBackgroundIDBFactory;
   manages PBackgroundTest;
   manages PBlob;
   manages PFileDescriptorSet;
+  manages PVsync;
 
 parent:
   // Only called at startup during mochitests to check the basic infrastructure.
   PBackgroundTest(nsCString testArg);
 
   PBackgroundIDBFactory(LoggingInfo loggingInfo);
 
+  PVsync();
+
 both:
   PBlob(BlobConstructorParams params);
 
   PFileDescriptorSet(FileDescriptor fd);
 };
 
 } // namespace ipc
 } // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/layout/ipc/PVsync.ipdl
@@ -0,0 +1,38 @@
+/* -*- 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 protocol PBackground;
+
+using class mozilla::TimeStamp from "mozilla/TimeStamp.h";
+
+namespace mozilla {
+namespace layout {
+
+/*
+ * The PVsync is a sub-protocol in PBackground and it is used to notify
+ * the vsync event from chrome to content process. It also provides the
+ * interfaces for content to observe/unobserve vsync event notifications.
+ */
+async protocol PVsync
+{
+  manager PBackground;
+
+child:
+  // Send vsync event from chrome to content process.
+  async Notify(TimeStamp aVsyncTimestamp);
+
+parent:
+  // Content process use these messages to acquire the vsync event.
+  async Observe();
+  async Unobserve();
+
+  // This message is never sent. Each PVsync actor will stay alive as long as
+  // its PBackground manager.
+  async __delete__();
+};
+
+} // namespace layout
+} // namespace mozilla
+
new file mode 100644
--- /dev/null
+++ b/layout/ipc/VsyncChild.cpp
@@ -0,0 +1,72 @@
+/* -*- 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 "VsyncChild.h"
+
+#include "mozilla/VsyncDispatcher.h"
+#include "nsThreadUtils.h"
+
+namespace mozilla {
+namespace layout {
+
+VsyncChild::VsyncChild()
+  : mObservingVsync(false)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+}
+
+VsyncChild::~VsyncChild()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+}
+
+bool
+VsyncChild::SendObserve()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  if (!mObservingVsync) {
+    PVsyncChild::SendObserve();
+    mObservingVsync = true;
+  }
+  return true;
+}
+
+bool
+VsyncChild::SendUnobserve()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  if (mObservingVsync) {
+    PVsyncChild::SendUnobserve();
+    mObservingVsync = false;
+  }
+  return true;
+}
+
+void
+VsyncChild::ActorDestroy(ActorDestroyReason aActorDestroyReason)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  mObserver = nullptr;
+}
+
+bool
+VsyncChild::RecvNotify(const TimeStamp& aVsyncTimestamp)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  if (mObservingVsync && mObserver) {
+    mObserver->NotifyVsync(aVsyncTimestamp);
+  }
+  return true;
+}
+
+void
+VsyncChild::SetVsyncObserver(VsyncObserver* aVsyncObserver)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  mObserver = aVsyncObserver;
+}
+
+} // namespace layout
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/layout/ipc/VsyncChild.h
@@ -0,0 +1,55 @@
+/* -*- 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_layout_ipc_VsyncChild_h
+#define mozilla_layout_ipc_VsyncChild_h
+
+#include "mozilla/layout/PVsyncChild.h"
+#include "nsRefPtr.h"
+
+namespace mozilla {
+
+class VsyncObserver;
+
+namespace ipc {
+class BackgroundChildImpl;
+}
+
+namespace layout {
+
+// The PVsyncChild actor receives a vsync event from the main process and
+// delivers it to the child process. Currently this is restricted to the main
+// thread only. The actor will stay alive until the process dies or its
+// PVsyncParent actor dies.
+class VsyncChild MOZ_FINAL : public PVsyncChild
+{
+  friend class mozilla::ipc::BackgroundChildImpl;
+
+public:
+  // Hide the SendObserve/SendUnobserve in PVsyncChild. We add an flag
+  // mObservingVsync to handle the race problem of unobserving vsync event.
+  bool SendObserve();
+  bool SendUnobserve();
+
+  // Bind a VsyncObserver into VsyncChild after ipc channel connected.
+  void SetVsyncObserver(VsyncObserver* aVsyncObserver);
+
+private:
+  VsyncChild();
+  virtual ~VsyncChild();
+
+  virtual bool RecvNotify(const TimeStamp& aVsyncTimestamp) MOZ_OVERRIDE;
+  virtual void ActorDestroy(ActorDestroyReason aActorDestroyReason) MOZ_OVERRIDE;
+
+  bool mObservingVsync;
+
+  // The content side vsync observer.
+  nsRefPtr<VsyncObserver> mObserver;
+};
+
+} // namespace layout
+} // namespatce mozilla
+
+#endif  // mozilla_layout_ipc_VsyncChild_h
new file mode 100644
--- /dev/null
+++ b/layout/ipc/VsyncParent.cpp
@@ -0,0 +1,112 @@
+/* -*- 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 "VsyncParent.h"
+
+#include "BackgroundParent.h"
+#include "BackgroundParentImpl.h"
+#include "gfxPlatform.h"
+#include "mozilla/unused.h"
+#include "nsIThread.h"
+#include "nsThreadUtils.h"
+#include "VsyncSource.h"
+
+namespace mozilla {
+
+using namespace ipc;
+
+namespace layout {
+
+/*static*/ already_AddRefed<VsyncParent>
+VsyncParent::Create()
+{
+  AssertIsOnBackgroundThread();
+  nsRefPtr<gfx::VsyncSource> vsyncSource = gfxPlatform::GetPlatform()->GetHardwareVsync();
+  nsRefPtr<VsyncParent> vsyncParent = new VsyncParent();
+  vsyncParent->mVsyncDispatcher = vsyncSource->GetRefreshTimerVsyncDispatcher();
+  return vsyncParent.forget();
+}
+
+VsyncParent::VsyncParent()
+  : mObservingVsync(false)
+  , mDestroyed(false)
+  , mBackgroundThread(NS_GetCurrentThread())
+{
+  MOZ_ASSERT(mBackgroundThread);
+  AssertIsOnBackgroundThread();
+}
+
+VsyncParent::~VsyncParent()
+{
+  // Since we use NS_INLINE_DECL_THREADSAFE_REFCOUNTING, we can't make sure
+  // VsyncParent is always released on the background thread.
+}
+
+bool
+VsyncParent::NotifyVsync(TimeStamp aTimeStamp)
+{
+  // Called on hardware vsync thread. We should post to current ipc thread.
+  MOZ_ASSERT(!IsOnBackgroundThread());
+  nsRefPtr<nsIRunnable> vsyncEvent =
+    NS_NewRunnableMethodWithArg<TimeStamp>(this,
+                                           &VsyncParent::DispatchVsyncEvent,
+                                           aTimeStamp);
+  MOZ_ALWAYS_TRUE(NS_SUCCEEDED(mBackgroundThread->Dispatch(vsyncEvent, NS_DISPATCH_NORMAL)));
+  return true;
+}
+
+void
+VsyncParent::DispatchVsyncEvent(TimeStamp aTimeStamp)
+{
+  AssertIsOnBackgroundThread();
+
+  // If we call NotifyVsync() when we handle ActorDestroy() message, we might
+  // still call DispatchVsyncEvent().
+  // Similarly, we might also receive RecvUnobserveVsync() when call
+  // NotifyVsync(). We use mObservingVsync and mDestroyed flags to skip this
+  // notification.
+  if (mObservingVsync && !mDestroyed) {
+    unused << SendNotify(aTimeStamp);
+  }
+}
+
+bool
+VsyncParent::RecvObserve()
+{
+  AssertIsOnBackgroundThread();
+  if (!mObservingVsync) {
+    mVsyncDispatcher->AddChildRefreshTimer(this);
+    mObservingVsync = true;
+    return true;
+  }
+  return false;
+}
+
+bool
+VsyncParent::RecvUnobserve()
+{
+  AssertIsOnBackgroundThread();
+  if (mObservingVsync) {
+    mVsyncDispatcher->RemoveChildRefreshTimer(this);
+    mObservingVsync = false;
+    return true;
+  }
+  return false;
+}
+
+void
+VsyncParent::ActorDestroy(ActorDestroyReason aReason)
+{
+  MOZ_ASSERT(!mDestroyed);
+  AssertIsOnBackgroundThread();
+  if (mObservingVsync) {
+    mVsyncDispatcher->RemoveChildRefreshTimer(this);
+  }
+  mVsyncDispatcher = nullptr;
+  mDestroyed = true;
+}
+
+} // namespace layout
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/layout/ipc/VsyncParent.h
@@ -0,0 +1,55 @@
+/* -*- 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_layout_ipc_VsyncParent_h
+#define mozilla_layout_ipc_VsyncParent_h
+
+#include "mozilla/layout/PVsyncParent.h"
+#include "mozilla/VsyncDispatcher.h"
+#include "nsCOMPtr.h"
+#include "nsRefPtr.h"
+
+class nsIThread;
+
+namespace mozilla {
+
+namespace ipc {
+class BackgroundParentImpl;
+}
+
+namespace layout {
+
+// Use PBackground thread in the main process to send vsync notifications to
+// content process. This actor will be released when its parent protocol calls
+// DeallocPVsyncParent().
+class VsyncParent MOZ_FINAL : public PVsyncParent,
+                              public VsyncObserver
+{
+  friend class mozilla::ipc::BackgroundParentImpl;
+
+private:
+  static already_AddRefed<VsyncParent> Create();
+
+  VsyncParent();
+  virtual ~VsyncParent();
+
+  virtual bool NotifyVsync(TimeStamp aTimeStamp) MOZ_OVERRIDE;
+
+  virtual bool RecvObserve() MOZ_OVERRIDE;
+  virtual bool RecvUnobserve() MOZ_OVERRIDE;
+  virtual void ActorDestroy(ActorDestroyReason aActorDestroyReason) MOZ_OVERRIDE;
+
+  void DispatchVsyncEvent(TimeStamp aTimeStamp);
+
+  bool mObservingVsync;
+  bool mDestroyed;
+  nsCOMPtr<nsIThread> mBackgroundThread;
+  nsRefPtr<RefreshTimerVsyncDispatcher> mVsyncDispatcher;
+};
+
+} //layout
+} //mozilla
+
+#endif  //mozilla_layout_ipc_VsyncParent_h
--- a/layout/ipc/moz.build
+++ b/layout/ipc/moz.build
@@ -3,25 +3,33 @@
 # 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/.
 
 EXPORTS.mozilla.layout += [
     'RenderFrameChild.h',
     'RenderFrameParent.h',
     'RenderFrameUtils.h',
+    'VsyncChild.h',
+    'VsyncParent.h',
 ]
 
 UNIFIED_SOURCES += [
     'RenderFrameChild.cpp',
     'RenderFrameParent.cpp',
 ]
 
+SOURCES += [
+    'VsyncChild.cpp',
+    'VsyncParent.cpp',
+]
+
 IPDL_SOURCES = [
     'PRenderFrame.ipdl',
+    'PVsync.ipdl',
 ]
 
 FAIL_ON_WARNINGS = True
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul'