Bug 1184283 - have compositor listen to its Widget for vsync
--- a/gfx/layers/ipc/CompositorBridgeParent.cpp
+++ b/gfx/layers/ipc/CompositorBridgeParent.cpp
@@ -70,17 +70,19 @@
#include "mozilla/ipc/GeckoChildProcessHost.h"
#include "mozilla/unused.h"
#include "mozilla/Hal.h"
#include "mozilla/HalTypes.h"
#include "mozilla/StaticPtr.h"
#ifdef MOZ_ENABLE_PROFILER_SPS
#include "ProfilerMarkers.h"
#endif
-#include "mozilla/VsyncDispatcher.h"
+
+extern PRLogModuleInfo *gVsyncLog;
+#define VSYNC_LOG(...) MOZ_LOG(gVsyncLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
#ifdef MOZ_WIDGET_GONK
#include "GeckoTouchDispatcher.h"
#include "nsScreenManagerGonk.h"
#endif
#ifdef MOZ_ANDROID_APZ
#include "AndroidBridge.h"
@@ -284,24 +286,23 @@ CompositorVsyncScheduler::Observer::Obse
{
}
CompositorVsyncScheduler::Observer::~Observer()
{
MOZ_ASSERT(!mOwner);
}
-bool
+void
CompositorVsyncScheduler::Observer::NotifyVsync(TimeStamp aVsyncTimestamp)
{
MutexAutoLock lock(mMutex);
- if (!mOwner) {
- return false;
+ if (mOwner) {
+ mOwner->NotifyVsync(aVsyncTimestamp);
}
- return mOwner->NotifyVsync(aVsyncTimestamp);
}
void
CompositorVsyncScheduler::Observer::Destroy()
{
MutexAutoLock lock(mMutex);
mOwner = nullptr;
}
@@ -322,17 +323,16 @@ CompositorVsyncScheduler::CompositorVsyn
, mSetDisplayMonitor("SetDisplayMonitor")
, mSetDisplayTask(nullptr)
#endif
#endif
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aWidget != nullptr);
mVsyncObserver = new Observer(this);
- mCompositorVsyncDispatcher = aWidget->GetCompositorVsyncDispatcher();
#ifdef MOZ_WIDGET_GONK
GeckoTouchDispatcher::GetInstance()->SetCompositorVsyncScheduler(this);
#if ANDROID_VERSION >= 19
RefPtr<nsScreenManagerGonk> screenManager = nsScreenManagerGonk::GetInstance();
screenManager->SetCompositorVsyncScheduler(this);
#endif
#endif
@@ -342,19 +342,17 @@ CompositorVsyncScheduler::CompositorVsyn
mAsapScheduling = gfxPrefs::LayersCompositionFrameRate() == 0 ||
gfxPlatform::IsInLayoutAsapMode();
}
CompositorVsyncScheduler::~CompositorVsyncScheduler()
{
MOZ_ASSERT(!mIsObservingVsync);
MOZ_ASSERT(!mVsyncObserver);
- // The CompositorVsyncDispatcher is cleaned up before this in the nsBaseWidget, which stops vsync listeners
mCompositorBridgeParent = nullptr;
- mCompositorVsyncDispatcher = nullptr;
}
#ifdef MOZ_WIDGET_GONK
#if ANDROID_VERSION >= 19
void
CompositorVsyncScheduler::SetDisplay(bool aDisplayEnable)
{
// SetDisplay() is usually called from nsScreenManager at main thread. Post
@@ -398,22 +396,27 @@ CompositorVsyncScheduler::CancelSetDispl
mDisplayEnabled = false;
}
#endif //ANDROID_VERSION >= 19
#endif //MOZ_WIDGET_GONK
void
CompositorVsyncScheduler::Destroy()
{
+ MOZ_ASSERT(CompositorBridgeParent::IsInCompositorThread());
+
+ VSYNC_LOG("VsyncScheduler %p Destroy\n", this);
+
if (!mVsyncObserver) {
// Destroy was already called on this object.
return;
}
- MOZ_ASSERT(CompositorBridgeParent::IsInCompositorThread());
+
UnobserveVsync();
+
mVsyncObserver->Destroy();
mVsyncObserver = nullptr;
#ifdef MOZ_WIDGET_GONK
#if ANDROID_VERSION >= 19
CancelSetDisplayTask();
#endif
#endif
@@ -589,26 +592,30 @@ CompositorVsyncScheduler::NeedsComposite
{
MOZ_ASSERT(CompositorBridgeParent::IsInCompositorThread());
return mNeedsComposite;
}
void
CompositorVsyncScheduler::ObserveVsync()
{
- MOZ_ASSERT(CompositorBridgeParent::IsInCompositorThread());
- mCompositorVsyncDispatcher->SetCompositorVsyncObserver(mVsyncObserver);
+ MOZ_ASSERT(mCompositorBridgeParent);
+ MOZ_ASSERT(mCompositorBridgeParent->GetWidget());
+ mCompositorBridgeParent->GetWidget()->AddVsyncObserver(mVsyncObserver);
mIsObservingVsync = true;
}
void
CompositorVsyncScheduler::UnobserveVsync()
{
- MOZ_ASSERT(CompositorBridgeParent::IsInCompositorThread());
- mCompositorVsyncDispatcher->SetCompositorVsyncObserver(nullptr);
+ // if we're being called from Destroy, the connection may have been
+ // already destroyed
+ if (mCompositorBridgeParent->GetWidget()) {
+ mCompositorBridgeParent->GetWidget()->RemoveVsyncObserver(mVsyncObserver);
+ }
mIsObservingVsync = false;
}
void
CompositorVsyncScheduler::DispatchTouchEvents(TimeStamp aVsyncTimestamp)
{
#ifdef MOZ_WIDGET_GONK
GeckoTouchDispatcher::GetInstance()->NotifyVsync(aVsyncTimestamp);
@@ -777,22 +784,30 @@ CompositorBridgeParent::RecvWillClose()
lts->mLayerManager = nullptr;
lts->mParent = nullptr;
});
mLayerManager->Destroy();
mLayerManager = nullptr;
mCompositionManager = nullptr;
}
+ if (mCompositorScheduler) {
+ mCompositorScheduler->Destroy();
+ }
+
if (mCompositor) {
mCompositor->DetachWidget();
mCompositor->Destroy();
mCompositor = nullptr;
}
+ // we shouldn't try to access the widget any more, since it'll go
+ // away shortly
+ mWidget = nullptr;
+
return true;
}
void CompositorBridgeParent::DeferredDestroy()
{
MOZ_ASSERT(!NS_IsMainThread());
MOZ_ASSERT(mCompositorThreadHolder);
mCompositorThreadHolder = nullptr;
@@ -937,16 +952,21 @@ CompositorBridgeParent::UpdateVisibleReg
// We need to recomposite to update the minimap.
ScheduleComposition();
}
}
void
CompositorBridgeParent::ActorDestroy(ActorDestroyReason why)
{
+ // at this point, we're going to assume our widget is unreachable --
+ // our scheduler cleanup (that needs the widget to unobserve) was done
+ // in WillClose
+ mWidget = nullptr;
+
CancelCurrentCompositeTask();
if (mForceCompositionTask) {
mForceCompositionTask->Cancel();
mForceCompositionTask = nullptr;
}
mPaused = true;
RemoveCompositor(mCompositorID);
@@ -967,17 +987,20 @@ CompositorBridgeParent::ActorDestroy(Act
mCompositionManager = nullptr;
if (mApzcTreeManager) {
mApzcTreeManager->ClearTree();
mApzcTreeManager = nullptr;
}
- mCompositorScheduler->Destroy();
+ if (mCompositorScheduler) {
+ mCompositorScheduler->Destroy();
+ mCompositorScheduler = nullptr;
+ }
// There are chances that the ref count reaches zero on the main thread shortly
// after this function returns while some ipdl code still needs to run on
// this thread.
// We must keep the compositor parent alive untill the code handling message
// reception is finished on this thread.
mSelfRef = this;
MessageLoop::current()->PostTask(FROM_HERE,
--- a/gfx/layers/ipc/CompositorBridgeParent.h
+++ b/gfx/layers/ipc/CompositorBridgeParent.h
@@ -32,17 +32,17 @@
#include "mozilla/layers/GeckoContentController.h"
#include "mozilla/layers/LayersMessages.h" // for TargetConfig
#include "mozilla/layers/PCompositorBridgeParent.h"
#include "mozilla/layers/ShadowLayersManager.h" // for ShadowLayersManager
#include "mozilla/layers/APZTestData.h"
#include "nsAutoPtr.h" // for nsRefPtr
#include "nsISupportsImpl.h"
#include "ThreadSafeRefcountingWithMainThreadDestruction.h"
-#include "mozilla/VsyncDispatcher.h"
+#include "gfxVsync.h"
class CancelableTask;
class MessageLoop;
class nsIWidget;
namespace mozilla {
namespace gfx {
class DrawTarget;
@@ -159,21 +159,23 @@ private:
void DispatchVREvents(TimeStamp aVsyncTimestamp);
void CancelCurrentSetNeedsCompositeTask();
#ifdef MOZ_WIDGET_GONK
#if ANDROID_VERSION >= 19
void CancelSetDisplayTask();
#endif
#endif
- class Observer final : public VsyncObserver
+ class Observer final : public gfx::VsyncObserver
{
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Observer, override)
+
public:
explicit Observer(CompositorVsyncScheduler* aOwner);
- virtual bool NotifyVsync(TimeStamp aVsyncTimestamp) override;
+ virtual void NotifyVsync(TimeStamp aVsyncTimestamp) override;
void Destroy();
private:
virtual ~Observer();
Mutex mMutex;
// Hold raw pointer to avoid mutual reference.
CompositorVsyncScheduler* mOwner;
};
@@ -184,17 +186,16 @@ private:
#ifdef COMPOSITOR_PERFORMANCE_WARNING
TimeStamp mExpectedComposeStartTime;
#endif
bool mAsapScheduling;
bool mIsObservingVsync;
uint32_t mNeedsComposite;
int32_t mVsyncNotificationsSkipped;
- RefPtr<CompositorVsyncDispatcher> mCompositorVsyncDispatcher;
RefPtr<CompositorVsyncScheduler::Observer> mVsyncObserver;
mozilla::Monitor mCurrentCompositeTaskMonitor;
CancelableTask* mCurrentCompositeTask;
mozilla::Monitor mSetNeedsCompositeMonitor;
CancelableTask* mSetNeedsCompositeTask;