gecko-dev/gfx/layers/ipc/CompositorParent.h

506 lines
17 KiB
C
Raw Normal View History

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=4 ts=8 et tw=80 : */
2012-05-21 11:12:37 +00:00
/* 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_layers_CompositorParent_h
#define mozilla_layers_CompositorParent_h
// Enable this pref to turn on compositor performance warning.
// This will print warnings if the compositor isn't meeting
// its responsiveness objectives:
// 1) Compose a frame within 15ms of receiving a ScheduleCompositeCall
// 2) Unless a frame was composited within the throttle threshold in
// which the deadline will be 15ms + throttle threshold
//#define COMPOSITOR_PERFORMANCE_WARNING
#include <stdint.h> // for uint64_t
#include "Layers.h" // for Layer
#include "base/basictypes.h" // for DISALLOW_EVIL_CONSTRUCTORS
#include "base/platform_thread.h" // for PlatformThreadId
#include "base/thread.h" // for Thread
#include "mozilla/Assertions.h" // for MOZ_ASSERT_HELPER2
#include "mozilla/Attributes.h" // for override
#include "mozilla/Monitor.h" // for Monitor
#include "mozilla/RefPtr.h" // for RefPtr
#include "mozilla/TimeStamp.h" // for TimeStamp
#include "mozilla/gfx/Point.h" // for IntSize
#include "mozilla/ipc/ProtocolUtils.h"
#include "mozilla/layers/GeckoContentController.h"
#include "mozilla/layers/LayersMessages.h" // for TargetConfig
#include "mozilla/layers/PCompositorParent.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"
class CancelableTask;
class MessageLoop;
class nsIWidget;
2011-12-15 20:07:25 +00:00
namespace mozilla {
namespace gfx {
class DrawTarget;
}
namespace layers {
class APZCTreeManager;
class AsyncCompositionManager;
class Compositor;
class CompositorParent;
class LayerManagerComposite;
class LayerTransactionParent;
struct ScopedLayerTreeRegistration
{
ScopedLayerTreeRegistration(uint64_t aLayersId,
Layer* aRoot,
GeckoContentController* aController);
~ScopedLayerTreeRegistration();
private:
uint64_t mLayersId;
};
class CompositorThreadHolder final
{
NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION(CompositorThreadHolder)
public:
CompositorThreadHolder();
base::Thread* GetCompositorThread() const {
return mCompositorThread;
}
private:
~CompositorThreadHolder();
base::Thread* const mCompositorThread;
static base::Thread* CreateCompositorThread();
static void DestroyCompositorThread(base::Thread* aCompositorThread);
friend class CompositorParent;
};
class CompositorScheduler
{
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CompositorScheduler)
explicit CompositorScheduler(CompositorParent* aCompositorParent);
virtual void ScheduleComposition() = 0;
virtual void CancelCurrentCompositeTask();
virtual bool NeedsComposite() = 0;
virtual void Composite(TimeStamp aTimestamp) = 0;
virtual void ScheduleTask(CancelableTask*, int);
virtual void ResumeComposition();
virtual void ForceComposeToTarget(gfx::DrawTarget* aTarget, const gfx::IntRect* aRect);
virtual void ComposeToTarget(gfx::DrawTarget* aTarget, const gfx::IntRect* aRect = nullptr);
virtual void Destroy();
const TimeStamp& GetLastComposeTime()
{
return mLastCompose;
}
#ifdef COMPOSITOR_PERFORMANCE_WARNING
const TimeStamp& GetExpectedComposeStartTime()
{
return mExpectedComposeStartTime;
}
#endif
protected:
virtual ~CompositorScheduler();
CompositorParent* mCompositorParent;
TimeStamp mLastCompose;
CancelableTask* mCurrentCompositeTask;
#ifdef COMPOSITOR_PERFORMANCE_WARNING
TimeStamp mExpectedComposeStartTime;
#endif
};
class CompositorSoftwareTimerScheduler final : public CompositorScheduler
{
public:
explicit CompositorSoftwareTimerScheduler(CompositorParent* aCompositorParent);
// from CompositorScheduler
virtual void ScheduleComposition() override;
virtual bool NeedsComposite() override;
virtual void Composite(TimeStamp aTimestamp) override;
void CallComposite();
private:
virtual ~CompositorSoftwareTimerScheduler();
};
/**
* Manages the vsync (de)registration and tracking on behalf of the
* compositor when it need to paint.
* Turns vsync notifications into scheduled composites.
**/
class CompositorVsyncScheduler final : public CompositorScheduler
{
public:
explicit CompositorVsyncScheduler(CompositorParent* aCompositorParent, nsIWidget* aWidget);
bool NotifyVsync(TimeStamp aVsyncTimestamp);
void SetNeedsComposite(bool aSchedule);
void OnForceComposeToTarget();
// from CompositorScheduler
virtual void ScheduleComposition() override;
virtual void CancelCurrentCompositeTask() override;
virtual bool NeedsComposite() override;
virtual void Composite(TimeStamp aVsyncTimestamp) override;
virtual void ForceComposeToTarget(gfx::DrawTarget* aTarget, const gfx::IntRect* aRect) override;
virtual void Destroy() override;
private:
virtual ~CompositorVsyncScheduler();
void NotifyCompositeTaskExecuted();
void ObserveVsync();
void UnobserveVsync();
void DispatchTouchEvents(TimeStamp aVsyncTimestamp);
void CancelCurrentSetNeedsCompositeTask();
class Observer final : public VsyncObserver
{
public:
explicit Observer(CompositorVsyncScheduler* aOwner);
virtual bool NotifyVsync(TimeStamp aVsyncTimestamp) override;
void Destroy();
private:
virtual ~Observer();
Mutex mMutex;
// Hold raw pointer to avoid mutual reference.
CompositorVsyncScheduler* mOwner;
};
bool mNeedsComposite;
bool mIsObservingVsync;
int32_t mVsyncNotificationsSkipped;
CompositorParent* mCompositorParent;
nsRefPtr<CompositorVsyncDispatcher> mCompositorVsyncDispatcher;
nsRefPtr<CompositorVsyncScheduler::Observer> mVsyncObserver;
mozilla::Monitor mCurrentCompositeTaskMonitor;
mozilla::Monitor mSetNeedsCompositeMonitor;
CancelableTask* mSetNeedsCompositeTask;
};
class CompositorUpdateObserver
{
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CompositorUpdateObserver);
virtual void ObserveUpdate(uint64_t aLayersId, bool aActive) = 0;
protected:
virtual ~CompositorUpdateObserver() {}
};
class CompositorParent final : public PCompositorParent,
public ShadowLayersManager
{
NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION(CompositorParent)
friend class CompositorScheduler;
public:
explicit CompositorParent(nsIWidget* aWidget,
bool aUseExternalSurfaceSize = false,
int aSurfaceWidth = -1, int aSurfaceHeight = -1);
// IToplevelProtocol::CloneToplevel()
virtual IToplevelProtocol*
CloneToplevel(const InfallibleTArray<mozilla::ipc::ProtocolFdMapping>& aFds,
base::ProcessHandle aPeerProcess,
mozilla::ipc::ProtocolCloneContext* aCtx) override;
virtual bool RecvGetFrameUniformity(FrameUniformityData* aOutData) override;
virtual bool RecvRequestOverfill() override;
virtual bool RecvWillStop() override;
virtual bool RecvStop() override;
virtual bool RecvPause() override;
virtual bool RecvResume() override;
virtual bool RecvNotifyHidden(const uint64_t& id) override { return true; }
virtual bool RecvNotifyVisible(const uint64_t& id) override { return true; }
virtual bool RecvNotifyChildCreated(const uint64_t& child) override;
virtual bool RecvAdoptChild(const uint64_t& child) override;
virtual bool RecvMakeSnapshot(const SurfaceDescriptor& aInSnapshot,
const gfx::IntRect& aRect) override;
virtual bool RecvMakeWidgetSnapshot(const SurfaceDescriptor& aInSnapshot) override;
virtual bool RecvFlushRendering() override;
virtual bool RecvGetTileSize(int32_t* aWidth, int32_t* aHeight) override;
virtual bool RecvNotifyRegionInvalidated(const nsIntRegion& aRegion) override;
virtual bool RecvStartFrameTimeRecording(const int32_t& aBufferSize, uint32_t* aOutStartIndex) override;
virtual bool RecvStopFrameTimeRecording(const uint32_t& aStartIndex, InfallibleTArray<float>* intervals) override;
// Unused for chrome <-> compositor communication (which this class does).
// @see CrossProcessCompositorParent::RecvRequestNotifyAfterRemotePaint
virtual bool RecvRequestNotifyAfterRemotePaint() override { return true; };
virtual void ActorDestroy(ActorDestroyReason why) override;
virtual void ShadowLayersUpdated(LayerTransactionParent* aLayerTree,
const uint64_t& aTransactionId,
const TargetConfig& aTargetConfig,
const InfallibleTArray<PluginWindowData>& aPlugins,
bool aIsFirstPaint,
bool aScheduleComposite,
uint32_t aPaintSequenceNumber,
bool aIsRepeatTransaction) override;
virtual void ForceComposite(LayerTransactionParent* aLayerTree) override;
virtual bool SetTestSampleTime(LayerTransactionParent* aLayerTree,
const TimeStamp& aTime) override;
virtual void LeaveTestMode(LayerTransactionParent* aLayerTree) override;
Bug 1113425 part 2 - Apply async properties when querying the animated transform; r=mattwoodrow In order to test off-main thread animations, we have a method that will return the animated transform value set on a shadow layer. This method will return null if the transform was not set by animation. However, in some situations we temporarily clear the animation transform. For example, when we synchronize a composite layer with its content layer, we reset the animation transform. Then, on the next composite, we will recalculate the animated value. If we try to query the animated transform value in between resetting it and the next composite we will get back null. To avoid a race condition, in ShadowLayersUpdated after potentially clearing the animated transform, we synchronously update the async properties on the layer transform in order to reinstate the animated transform (so it is there when we go to query it). However we *only* do this when the mIsTesting flag is set which is true whenever we have the refresh driver under test control. Furthermore, we only do it when we already have a pending composite task to better match conditions under regular operation. In test_deferred_start.html, however, we specifically need to test without putting the refresh driver under test control. As a result mIsTesting will be false and we can encounter a race condition when querying the animated transform. To work around this, this patch makes us *also* update async properties when fetching the animated transform value. The method for getting the animated transform value is only used for testing so it should have no effect on the regular compositing behavior. It would seem that we could then remove the call from ShadowLayersUpdated but doing this caused a small number of test cases to fail. In particular one test for *opacity* in test_animations_omta.html was failing at the end of the animation because we ended up with a stale opacity animation value on the compositor which the synchronous update was previously removing. The test, in this case, should be ignoring the value on the compositor but, unlike transform, there is no flag for indicating whether or not the opacity on shadow layers has been set by animations. As a result, this patch leaves the call that triggers a synchronous update in test mode when updating shadow layers.
2015-03-17 09:38:12 +00:00
virtual void ApplyAsyncProperties(LayerTransactionParent* aLayerTree)
override;
virtual void GetAPZTestData(const LayerTransactionParent* aLayerTree,
APZTestData* aOutData) override;
virtual void SetConfirmedTargetAPZC(const LayerTransactionParent* aLayerTree,
const uint64_t& aInputBlockId,
const nsTArray<ScrollableLayerGuid>& aTargets) override;
virtual AsyncCompositionManager* GetCompositionManager(LayerTransactionParent* aLayerTree) override { return mCompositionManager; }
/**
* This forces the is-first-paint flag to true. This is intended to
* be called by the widget code when it loses its viewport information
* (or for whatever reason wants to refresh the viewport information).
* The information refresh happens because the compositor will call
* SetFirstPaintViewport on the next frame of composition.
*/
void ForceIsFirstPaint();
2011-12-22 15:59:53 +00:00
void Destroy();
static void SetShadowProperties(Layer* aLayer);
void NotifyChildCreated(const uint64_t& aChild);
void AsyncRender();
2012-02-09 22:39:04 +00:00
// Can be called from any thread
void ScheduleRenderOnCompositorThread();
void SchedulePauseOnCompositorThread();
/**
* Returns true if a surface was obtained and the resume succeeded; false
* otherwise.
*/
bool ScheduleResumeOnCompositorThread();
bool ScheduleResumeOnCompositorThread(int width, int height);
virtual void ScheduleComposition();
void NotifyShadowTreeTransaction(uint64_t aId, bool aIsFirstPaint,
bool aScheduleComposite, uint32_t aPaintSequenceNumber,
bool aIsRepeatTransaction);
/**
* Check rotation info and schedule a rendering task if needed.
* Only can be called from compositor thread.
*/
void ScheduleRotationOnCompositorThread(const TargetConfig& aTargetConfig, bool aIsFirstPaint);
/**
* Returns the unique layer tree identifier that corresponds to the root
* tree of this compositor.
*/
uint64_t RootLayerTreeId();
/**
* Returns a pointer to the compositor corresponding to the given ID.
*/
static CompositorParent* GetCompositor(uint64_t id);
/**
* Returns the compositor thread's message loop.
*
* This message loop is used by CompositorParent and ImageBridgeParent.
*/
static MessageLoop* CompositorLoop();
/**
* Creates the compositor thread and the global compositor map.
*/
static void StartUp();
/**
* Waits for all [CrossProcess]CompositorParent's to be gone,
* and destroys the compositor thread and global compositor map.
*
* Does not return until all of that has completed.
*/
static void ShutDown();
/**
* Allocate an ID that can be used to refer to a layer tree and
* associated resources that live only on the compositor thread.
*
* Must run on the content main thread.
*/
static uint64_t AllocateLayerTreeId();
/**
* Release compositor-thread resources referred to by |aID|.
*
* Must run on the content main thread.
*/
static void DeallocateLayerTreeId(uint64_t aId);
/**
* Set aController as the pan/zoom callback for the subtree referred
* to by aLayersId.
*
* Must run on content main thread.
*/
static void SetControllerForLayerTree(uint64_t aLayersId,
GeckoContentController* aController);
/**
* This returns a reference to the APZCTreeManager to which
* pan/zoom-related events can be sent.
*/
static APZCTreeManager* GetAPZCTreeManager(uint64_t aLayersId);
/**
* A new child process has been configured to push transactions
* directly to us. Transport is to its thread context.
*/
static PCompositorParent*
Create(Transport* aTransport, ProcessId aOtherProcess);
struct LayerTreeState {
LayerTreeState();
~LayerTreeState();
nsRefPtr<Layer> mRoot;
nsRefPtr<GeckoContentController> mController;
CompositorParent* mParent;
LayerManagerComposite* mLayerManager;
// Pointer to the CrossProcessCompositorParent. Used by APZCs to share
// their FrameMetrics with the corresponding child process that holds
// the PCompositorChild
PCompositorParent* mCrossProcessParent;
TargetConfig mTargetConfig;
APZTestData mApzTestData;
LayerTransactionParent* mLayerTree;
nsTArray<PluginWindowData> mPluginData;
bool mUpdatedPluginDataAvailable;
nsRefPtr<CompositorUpdateObserver> mLayerTreeReadyObserver;
nsRefPtr<CompositorUpdateObserver> mLayerTreeClearedObserver;
};
/**
* Lookup the indirect shadow tree for |aId| and return it if it
* exists. Otherwise null is returned. This must only be called on
* the compositor thread.
*/
static LayerTreeState* GetIndirectShadowTree(uint64_t aId);
/**
* Used by the profiler to denote when a vsync occured
*/
static void PostInsertVsyncProfilerMarker(mozilla::TimeStamp aVsyncTimestamp);
static void RequestNotifyLayerTreeReady(uint64_t aLayersId, CompositorUpdateObserver* aObserver);
static void RequestNotifyLayerTreeCleared(uint64_t aLayersId, CompositorUpdateObserver* aObserver);
static void SwapLayerTreeObservers(uint64_t aLayer, uint64_t aOtherLayer);
float ComputeRenderIntegrity();
/**
* Returns true if the calling thread is the compositor thread.
*/
static bool IsInCompositorThread();
nsIWidget* GetWidget() { return mWidget; }
protected:
// Protected destructor, to discourage deletion outside of Release():
virtual ~CompositorParent();
void DeferredDestroy();
virtual PLayerTransactionParent*
AllocPLayerTransactionParent(const nsTArray<LayersBackend>& aBackendHints,
2013-07-08 15:48:39 +00:00
const uint64_t& aId,
TextureFactoryIdentifier* aTextureFactoryIdentifier,
bool* aSuccess) override;
virtual bool DeallocPLayerTransactionParent(PLayerTransactionParent* aLayers) override;
virtual void ScheduleTask(CancelableTask*, int);
void CompositeToTarget(gfx::DrawTarget* aTarget, const gfx::IntRect* aRect = nullptr);
void ForceComposeToTarget(gfx::DrawTarget* aTarget, const gfx::IntRect* aRect = nullptr);
void SetEGLSurfaceSize(int width, int height);
void InitializeLayerManager(const nsTArray<LayersBackend>& aBackendHints);
2012-02-14 23:36:33 +00:00
void PauseComposition();
void ResumeComposition();
void ResumeCompositionAndResize(int width, int height);
void ForceComposition();
void CancelCurrentCompositeTask();
2012-02-14 23:36:33 +00:00
/**
* Add a compositor to the global compositor map.
*/
static void AddCompositor(CompositorParent* compositor, uint64_t* id);
/**
* Remove a compositor from the global compositor map.
*/
static CompositorParent* RemoveCompositor(uint64_t id);
/**
* Return true if current state allows compositing, that is
* finishing a layers transaction.
*/
bool CanComposite();
void DidComposite();
nsRefPtr<LayerManagerComposite> mLayerManager;
nsRefPtr<Compositor> mCompositor;
RefPtr<AsyncCompositionManager> mCompositionManager;
nsIWidget* mWidget;
TimeStamp mTestTime;
bool mIsTesting;
uint64_t mPendingTransaction;
bool mPaused;
bool mUseExternalSurfaceSize;
gfx::IntSize mEGLSurfaceSize;
mozilla::Monitor mPauseCompositionMonitor;
mozilla::Monitor mResumeCompositionMonitor;
uint64_t mCompositorID;
uint64_t mRootLayerTreeID;
bool mOverrideComposeReadiness;
CancelableTask* mForceCompositionTask;
nsRefPtr<APZCTreeManager> mApzcTreeManager;
nsRefPtr<CompositorThreadHolder> mCompositorThreadHolder;
nsRefPtr<CompositorScheduler> mCompositorScheduler;
2011-12-15 20:07:19 +00:00
DISALLOW_EVIL_CONSTRUCTORS(CompositorParent);
};
} // layers
} // mozilla
#endif // mozilla_layers_CompositorParent_h