Introduce the notion of an APZ sampler thread

RESOLVED FIXED in Firefox 60

Status

()

enhancement
P3
normal
RESOLVED FIXED
Last year
Last year

People

(Reporter: kats, Assigned: kats)

Tracking

unspecified
mozilla60
Points:
---
Dependency tree / graph

Firefox Tracking Flags

(firefox60 fixed)

Details

(Whiteboard: [gfx-noted])

Attachments

(7 attachments)

Right now the APZ has the notion of a "controller thread" which is an abstract thread that maps to different actual threads on different platforms or under different configurations. For instance on macOS the controller thread is the main process' main thread, but on Windows with the GPU process enabled the controller thread is the compositor thread in the GPU process. (although that will change at some point to be the main thread in the GPU process).

We want to introduce an analogous notion of a "sampler thread" which is the thread on which the APZ scroll offsets get sampled. This thread will also be responsible to delivering layer tree changes to APZ (i.e. UpdateHitTestingTree will be called on this thread).

We want this in order to make APZ work better with async scene building in webrender, because with webrender enabled we want the "sampler thread" to be the render backend thread. Currently in pretty much every configuration it is the compositor thread (in the GPU process or the main process, wherever it is).
Also if anybody has a better suggestion to the name than "sampler thread" please suggest it.

Try push with my current patchset: https://treeherder.mozilla.org/#/jobs?repo=try&revision=149b4912377799016aa2cbfe52a7b98a19f0426c

This isn't really "complete" but I want to land these incrementally to avoid building up a massive patch queue that I need to constantly rebase.
Comment hidden (mozreview-request)
Comment hidden (mozreview-request)
Comment hidden (mozreview-request)
Comment hidden (mozreview-request)
Comment hidden (mozreview-request)
Comment hidden (mozreview-request)
Comment hidden (mozreview-request)
Try push is looking good. I added some jobs for other platforms too, those are still pending. In the meantime, putting this first slew of patches up for review. I have more patches in progress, for which I'll file another bug.
Assignee: nobody → bugmail
Priority: -- → P3
Whiteboard: [gfx-noted]
I made a mistake in part 3; new patches coming.
Comment hidden (mozreview-request)
Comment hidden (mozreview-request)
Comment hidden (mozreview-request)
Comment hidden (mozreview-request)
Comment hidden (mozreview-request)
Comment hidden (mozreview-request)
Comment hidden (mozreview-request)
(In reply to Kartikaya Gupta (email:kats@mozilla.com) from comment #1)
> Try push with my current patchset:
> https://treeherder.mozilla.org/#/
> jobs?repo=try&revision=149b4912377799016aa2cbfe52a7b98a19f0426c

This try push had an android test perma-fail. It was due to the mistake in part 3. Here's the new try push with it fixed: https://treeherder.mozilla.org/#/jobs?repo=try&revision=707067323b326adbb05893ea1a738ac5e0077ee3

> This isn't really "complete" but I want to land these incrementally to avoid
> building up a massive patch queue that I need to constantly rebase.

To be clear what I mean by "this isn't really complete" is that the APZSampler interface added in the last patch still needs more methods to be added to it. But this is all I want to do in this bug.

Comment 19

Last year
mozreview-review
Comment on attachment 8954876 [details]
Bug 1441916 - Add hooks in APZCTreeManager to respond to layer tree changes.

https://reviewboard.mozilla.org/r/224026/#review230336

::: gfx/layers/apz/src/APZCTreeManager.h:128
(Diff revision 2)
> +   * some other compositor. That other compositor's APZCTreeManager is also
> +   * provided. This allows APZCTreeManager to transfer any necessary state
> +   * from the old APZCTreeManager related to that layers id.
> +   * This function must be called on the compositor thread.
> +   */
> +  void NotifyLayerTreeAdopted(const uint64_t& aLayerTree,

We generally (including elsewhere in this class) pass uint64_t by value.

|aLayersId| might make more sense as a parameter name?

::: gfx/layers/ipc/CompositorBridgeParent.cpp:1797
(Diff revision 2)
>    if (iter != sIndirectLayerTrees.end()) {
>      CompositorBridgeParent* parent = iter->second.mParent;
>      if (parent) {
>        parent->ClearApproximatelyVisibleRegions(aId, Nothing());
> +      if (RefPtr<APZCTreeManager> apzctm = parent->GetAPZCTreeManager()) {
> +        apzctm->NotifyLayerTreeRemoved(aId);

There are some other places that erase a layers id, like ActorDestroy(). I'm guessing we don't need to send a notification there because things are being torn down anyways, but maybe it's worth adding a note to APZCTreeManager::NotifyLayerTreeRemoved() that it won't be called in shutdown situations?
Attachment #8954876 - Flags: review?(botond) → review+

Comment 20

Last year
mozreview-review
Comment on attachment 8954877 [details]
Bug 1441916 - Replace the code to clear focus targets with the simpler hook.

https://reviewboard.mozilla.org/r/224028/#review230364

::: gfx/layers/apz/src/APZCTreeManager.cpp:280
(Diff revision 2)
>  void
>  APZCTreeManager::NotifyLayerTreeRemoved(const uint64_t& aLayersId)
>  {
>    APZThreadUtils::AssertOnCompositorThread();
> +
> +  mFocusState.RemoveFocusTarget(aLayersId);

This comment is independent of your change, but shouldn't FocusState::RemoveFocusTarget() update FocusState::mFocus{Horizontal,Vertical}Target (basically, run all the code in FocusState::Update() that comes after saving the new target in mFocusTree)?
Attachment #8954877 - Flags: review?(botond) → review+

Comment 21

Last year
mozreview-review
Comment on attachment 8954878 [details]
Bug 1441916 - Move APZTestData from the LayerTreeState structure into the APZ.

https://reviewboard.mozilla.org/r/224030/#review230378

::: gfx/layers/apz/src/APZCTreeManager.h:496
(Diff revision 2)
>  
>    void UpdateWheelTransaction(
>        LayoutDeviceIntPoint aRefPoint,
>        EventMessage aEventMessage) override;
>  
> +  Maybe<APZTestData> GetAPZTestData(const uint64_t& aLayersId);

Take by value

::: gfx/layers/apz/src/APZCTreeManager.h:724
(Diff revision 2)
>    friend class CheckerboardFlushObserver;
>    RefPtr<CheckerboardFlushObserver> mFlushObserver;
>  
> +  // Map from layers id to APZTestData. Accesses and mutations must be
> +  // protected by the mTestDataLock.
> +  std::unordered_map<uint64_t, APZTestData> mTestData;

APZTestData has the potential to be a fairly heavyweight data structure, as it can contain data about an arbitrarily large number of paints etc.

For this reason, I would prefer that we stored it by UniquePtr. This would avoid the two copies of the data the code currently does when adopting a layer tree, and two of the copies made during GetAPZTestData() (the latter would still need to make one copy into the target object).

::: gfx/layers/apz/src/APZCTreeManager.h:725
(Diff revision 2)
>    RefPtr<CheckerboardFlushObserver> mFlushObserver;
>  
> +  // Map from layers id to APZTestData. Accesses and mutations must be
> +  // protected by the mTestDataLock.
> +  std::unordered_map<uint64_t, APZTestData> mTestData;
> +  mutable mozilla::Mutex mTestDataLock;

Please add this lock to the lock ordering comment at the top of APZCTreeManager.h.

Based on the usage, it should come after the tree lock (it looks like it doesn't matter whether it comes before or after an APZC lock, though we should still pick an ordering between them).

::: gfx/layers/ipc/CompositorBridgeParent.cpp:1379
(Diff revision 2)
>  
>  void
>  CompositorBridgeParent::GetAPZTestData(const uint64_t& aLayersId,
>                                         APZTestData* aOutData)
>  {
> -  MOZ_ASSERT(aLayersId == 0 || aLayersId == mRootLayerTreeID);
> +  uint64_t layersId = (aLayersId == 0 ? mRootLayerTreeID : aLayersId);

Why are we getting rid of the assert?
Attachment #8954878 - Flags: review?(botond)

Comment 22

Last year
mozreview-review
Comment on attachment 8954879 [details]
Bug 1441916 - Remove calls to GetIndirectShadowTree inside APZCTreeManager.

https://reviewboard.mozilla.org/r/224032/#review230388

::: gfx/layers/apz/src/APZCTreeManager.cpp:72
(Diff revision 2)
>  typedef CompositorBridgeParent::LayerTreeState LayerTreeState;
>  
>  float APZCTreeManager::sDPI = 160.0;
>  
>  struct APZCTreeManager::TreeBuildingState {
> -  TreeBuildingState(const LayerTreeState* const aLayerTreeState,
> +  TreeBuildingState(const uint64_t& aRootLayersId,

(Take by value)

::: gfx/layers/apz/src/APZCTreeManager.cpp:80
(Diff revision 2)
> -    , mIsFirstPaint(aIsFirstPaint)
>      , mOriginatingLayersId(aOriginatingLayersId)
>      , mPaintLogger(aTestData, aPaintSequence)
>    {
> +    CompositorBridgeParent::CallWithIndirectShadowTree(aRootLayersId,
> +        [&](LayerTreeState& aState) -> void {

For a lambda that only captures one or two variables, I prefer listing the captures explicitly instead of using a capture-default.

In this case, it's sufficient to capture "this":

  [this](LayerTreeState& aState) -> ...

::: gfx/layers/apz/src/APZCTreeManager.cpp:565
(Diff revision 2)
>          if (aNode->GetLayersId() != lastLayersId) {
>            // If we walked into or out of a subtree, we need to get the new
>            // pipeline id.
> -          const LayerTreeState* state = CompositorBridgeParent::GetIndirectShadowTree(aNode->GetLayersId());
> -          if (!(state && state->mWrBridge)) {
> +          RefPtr<WebRenderBridgeParent> wrBridge;
> +          CompositorBridgeParent::CallWithIndirectShadowTree(aNode->GetLayersId(),
> +              [&](LayerTreeState& aState) -> void {

Similarly, this lambda need only capture "&wrBridge".

::: gfx/layers/apz/src/APZCTreeManager.cpp:824
(Diff revision 2)
> -  if (!(state && state->mController.get())) {
> +  // TreeBuildingState, and update them as we change layers id during the
> +  // traversal
> +  RefPtr<GeckoContentController> geckoContentController;
> +  RefPtr<MetricsSharingController> crossProcessSharingController;
> +  CompositorBridgeParent::CallWithIndirectShadowTree(aLayersId,
> +      [&](LayerTreeState& aState) -> void {

I don't love that a lambda parameter named |aState| of type LayerTreeState& shadows an enclosing function parameter named |aState| of type TreeBuildingState&. Consider renaming one of them.
Attachment #8954879 - Flags: review?(botond) → review+
(In reply to Botond Ballo [:botond] from comment #22)
> I don't love that a lambda parameter named |aState| of type LayerTreeState&
> shadows an enclosing function parameter named |aState| of type
> TreeBuildingState&. Consider renaming one of them.

(Though I suppose the latter does come from a *shadow* tree </groaner>).

Comment 24

Last year
mozreview-review
Comment on attachment 8954880 [details]
Bug 1441916 - Introduce the notion of the APZ sampler thread.

https://reviewboard.mozilla.org/r/224034/#review230398

::: gfx/layers/apz/util/APZThreadUtils.cpp:49
(Diff revision 2)
>  
>  /*static*/ void
> -APZThreadUtils::AssertOnCompositorThread()
> +APZThreadUtils::AssertOnSamplerThread()
>  {
>    if (GetThreadAssertionsEnabled()) {
> -    Compositor::AssertOnCompositorThread();
> +    MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());

Any reason we're changing the implementation from "CompositorThreadHolder::Loop() == MessageLoop::current()" (what Compositor::AssertOnCompositorThread() did) to  "CompositorThread()->thread_id() == PlatformThread::CurrentId()" (what this does)?
Attachment #8954880 - Flags: review?(botond) → review+

Comment 25

Last year
mozreview-review
Comment on attachment 8954881 [details]
Bug 1441916 - Modify the static GetAPZCTreeManager to return an IAPZCTreeManager.

https://reviewboard.mozilla.org/r/224036/#review230400
Attachment #8954881 - Flags: review?(botond) → review+
(In reply to Botond Ballo [:botond] from comment #21)
> For this reason, I would prefer that we stored it by UniquePtr. This would
> avoid the two copies of the data the code currently does when adopting a
> layer tree, and two of the copies made during GetAPZTestData()

(One of those copies in each case may actually be a move, but I think my point still applies.)

Comment 27

Last year
mozreview-review
Comment on attachment 8954882 [details]
Bug 1441916 - Introduce an APZSampler interface for APZCTreeManager.

https://reviewboard.mozilla.org/r/224038/#review230402

::: gfx/layers/apz/public/APZSampler.h:27
(Diff revision 2)
> + * This interface is used to interact with the APZ code from the compositor
> + * thread. It internally redispatches the functions to the sampler thread
> + * in the case where the two threads are not the same.
> + */
> +class APZSampler {
> +  NS_INLINE_DECL_THREADSAFE_VIRTUAL_REFCOUNTING(APZSampler)

Why virtual?

::: gfx/layers/apz/public/APZSampler.h:47
(Diff revision 2)
> +                            const WebRenderScrollData& aScrollData,
> +                            bool aIsFirstPaint,
> +                            uint64_t aOriginatingLayersId,
> +                            uint32_t aPaintSequenceNumber);
> +
> +  void NotifyLayerTreeAdopted(const uint64_t& aLayerTree,

(Take by value)

::: gfx/layers/apz/public/APZSampler.h:51
(Diff revision 2)
> +
> +  void NotifyLayerTreeAdopted(const uint64_t& aLayerTree,
> +                              const RefPtr<APZSampler>& aOldSampler);
> +  void NotifyLayerTreeRemoved(const uint64_t& aLayerTree);
> +
> +  Maybe<APZTestData> GetAPZTestData(const uint64_t& aLayersId);

(This signature will presumably change to UniquePtr<APZTestData> after addressing the comment on the previous patch.)

::: gfx/layers/apz/src/APZCTreeManager.cpp:524
(Diff revision 2)
>                                        const WebRenderScrollData& aScrollData,
>                                        bool aIsFirstPaint,
>                                        uint64_t aOriginatingLayersId,
>                                        uint32_t aPaintSequenceNumber)
>  {
> +  APZThreadUtils::AssertOnSamplerThread();

We already have an assert in UpdateHitTestingTreeImpl(). Pick one or the other?

::: gfx/layers/ipc/CompositorBridgeParent.cpp:663
(Diff revision 2)
>  
>    mCompositionManager = nullptr;
>  
> -  if (mApzcTreeManager) {
> -    mApzcTreeManager->ClearTree();
> -    mApzcTreeManager = nullptr;
> +  if (mApzSampler) {
> +    mApzSampler->ClearTree();
> +    mApzSampler = nullptr;

Since both mApzcTreeManager and mApzSampler are strong references, don't we need to clear both?
Attachment #8954882 - Flags: review?(botond) → review+
(In reply to Botond Ballo [:botond] from comment #19)
> 
> We generally (including elsewhere in this class) pass uint64_t by value.

Sorry, I'm used to doing it with const-ref because we do that in a lot of places. But yeah, updated to just pass by value here.

> |aLayersId| might make more sense as a parameter name?

Yup, fixed also

> ::: gfx/layers/ipc/CompositorBridgeParent.cpp:1797
> There are some other places that erase a layers id, like ActorDestroy(). I'm
> guessing we don't need to send a notification there because things are being
> torn down anyways, but maybe it's worth adding a note to
> APZCTreeManager::NotifyLayerTreeRemoved() that it won't be called in
> shutdown situations?

Good point, updated documentation.

(In reply to Botond Ballo [:botond] from comment #20)
> This comment is independent of your change, but shouldn't
> FocusState::RemoveFocusTarget() update
> FocusState::mFocus{Horizontal,Vertical}Target (basically, run all the code
> in FocusState::Update() that comes after saving the new target in
> mFocusTree)?

Yeah that sounds like a reasonable thing to do. I'm guessing that when a layer tree is removed we usually get another focus state update in short order anyway and so there's not really a user-observable issue in practice. But yeah, I guess for correctness it would be good to do this. I've filed bug 1442409 for it.

(In reply to Botond Ballo [:botond] from comment #21)
> Take by value

Done

> ::: gfx/layers/apz/src/APZCTreeManager.h:724
> APZTestData has the potential to be a fairly heavyweight data structure, as
> it can contain data about an arbitrarily large number of paints etc.
> 
> For this reason, I would prefer that we stored it by UniquePtr. This would
> avoid the two copies of the data the code currently does when adopting a
> layer tree, and two of the copies made during GetAPZTestData() (the latter
> would still need to make one copy into the target object).

Yeah, good point. I've changed it to be stored as a UniquePtr. However, since GetAPZTestData shouldn't return a raw pointer, the return would have to stay a Maybe<>, which would would still make copies. Instead what I did there was pass the destination pointer in as an out-param and have the function implementation copy directly into that, which avoids the unnecessary copies.

The reason GetAPZTestData shouldn't return a raw pointer is because if the compositor thread is not the same as the sampler thread, the function will be called on the compositor thread and will have to block on the sampler thread to actually do the read from the map, and then will have to return that back. And having to pass that return value back across threads means we'll need to pass a copy rather than a raw pointer to a data structure (which can be deleted on the render thread while the compositor thread is holding the raw pointer). However the out-pointer approach should still work.

> ::: gfx/layers/apz/src/APZCTreeManager.h:725
> Please add this lock to the lock ordering comment at the top of
> APZCTreeManager.h.
> 
> Based on the usage, it should come after the tree lock (it looks like it
> doesn't matter whether it comes before or after an APZC lock, though we
> should still pick an ordering between them).

Done. I put it after the APZC lock, because it's conceivable that we'll want to write stuff into APZTestData from somewhere inside APZC, holding the APZC lock. However it's unlikely that we'll need to enter an APZC lock while we're in the midst of mutating the test data.

> ::: gfx/layers/ipc/CompositorBridgeParent.cpp:1379
> > -  MOZ_ASSERT(aLayersId == 0 || aLayersId == mRootLayerTreeID);
> > +  uint64_t layersId = (aLayersId == 0 ? mRootLayerTreeID : aLayersId);
> 
> Why are we getting rid of the assert?

The CrossProcessCompositorBridgeParent version of this function now delegates its implementation to this CompositorBridgeParent version, which means the layers id being passed in can now be for any of the sub-layer-trees managed by this CompositorBridgeParent. So the assertion as it was became incorrect.

(In reply to Botond Ballo [:botond] from comment #22)
> > -  TreeBuildingState(const LayerTreeState* const aLayerTreeState,
> > +  TreeBuildingState(const uint64_t& aRootLayersId,
> 
> (Take by value)

Fixed

> ::: gfx/layers/apz/src/APZCTreeManager.cpp:80
> For a lambda that only captures one or two variables, I prefer listing the
> captures explicitly instead of using a capture-default.
> 
> In this case, it's sufficient to capture "this":
> 
>   [this](LayerTreeState& aState) -> ...

Done

> ::: gfx/layers/apz/src/APZCTreeManager.cpp:565
> Similarly, this lambda need only capture "&wrBridge".

Done

> ::: gfx/layers/apz/src/APZCTreeManager.cpp:824
> I don't love that a lambda parameter named |aState| of type LayerTreeState&
> shadows an enclosing function parameter named |aState| of type
> TreeBuildingState&. Consider renaming one of them.

Renamed the inner one to |lts|.

(In reply to Botond Ballo [:botond] from comment #23)
> (Though I suppose the latter does come from a *shadow* tree </groaner>).

Lol!

(In reply to Botond Ballo [:botond] from comment #24)
> Any reason we're changing the implementation from
> "CompositorThreadHolder::Loop() == MessageLoop::current()" (what
> Compositor::AssertOnCompositorThread() did) to 
> "CompositorThread()->thread_id() == PlatformThread::CurrentId()" (what this
> does)?

The two assertions should be functionally equivalent - as such it seemed redundant to have two of them. I just got rid of the one that was easier to get rid of (fewer call sites, and almost entirely in APZ).

(In reply to Botond Ballo [:botond] from comment #27)
> 
> Why virtual?

Good catch, it doesn't need to be. Updated.

> ::: gfx/layers/apz/public/APZSampler.h:47
> > +  void NotifyLayerTreeAdopted(const uint64_t& aLayerTree,
> 
> (Take by value)

Fixed

> ::: gfx/layers/apz/public/APZSampler.h:51
> (This signature will presumably change to UniquePtr<APZTestData> after
> addressing the comment on the previous patch.)

I changed it to take the out-param instead.

> ::: gfx/layers/apz/src/APZCTreeManager.cpp:524
> >  {
> > +  APZThreadUtils::AssertOnSamplerThread();
> 
> We already have an assert in UpdateHitTestingTreeImpl(). Pick one or the
> other?

I think on balance I prefer it in the two call sites than in the Impl. So I removed the one in the Impl.

> ::: gfx/layers/ipc/CompositorBridgeParent.cpp:663
> Since both mApzcTreeManager and mApzSampler are strong references, don't we
> need to clear both?

Good catch! I think at some point I was trying to get rid of mApzcTreeManager entirely and this is probably leftover from that. I'll fix this up.

I'll make sure the updated patch set compiles and passes tests, then update on this bug.
(In reply to Kartikaya Gupta (email:kats@mozilla.com) from comment #28)
> > ::: gfx/layers/ipc/CompositorBridgeParent.cpp:1379
> > > -  MOZ_ASSERT(aLayersId == 0 || aLayersId == mRootLayerTreeID);
> > > +  uint64_t layersId = (aLayersId == 0 ? mRootLayerTreeID : aLayersId);
> > 
> > Why are we getting rid of the assert?
> 
> The CrossProcessCompositorBridgeParent version of this function now
> delegates its implementation to this CompositorBridgeParent version, which
> means the layers id being passed in can now be for any of the
> sub-layer-trees managed by this CompositorBridgeParent. So the assertion as
> it was became incorrect.

Ah, good point.

> > ::: gfx/layers/apz/public/APZSampler.h:51
> > (This signature will presumably change to UniquePtr<APZTestData> after
> > addressing the comment on the previous patch.)
> 
> I changed it to take the out-param instead.

I'm not sure what I was thinking when I wrote that. Obviously, it can't be a *unique* pointer while the APZ test data is still inside APZCTM's map. We could have made it a shared pointer, but your idea of passing an out-param through is even better.
Comment hidden (mozreview-request)
Comment hidden (mozreview-request)
Comment hidden (mozreview-request)
Comment hidden (mozreview-request)
Comment hidden (mozreview-request)
Comment hidden (mozreview-request)
Comment hidden (mozreview-request)

Comment 38

Last year
mozreview-review
Comment on attachment 8954878 [details]
Bug 1441916 - Move APZTestData from the LayerTreeState structure into the APZ.

https://reviewboard.mozilla.org/r/224030/#review230694

::: gfx/layers/apz/src/APZCTreeManager.h:500
(Diff revisions 2 - 3)
>  
>    void UpdateWheelTransaction(
>        LayoutDeviceIntPoint aRefPoint,
>        EventMessage aEventMessage) override;
>  
> -  Maybe<APZTestData> GetAPZTestData(const uint64_t& aLayersId);
> +  bool GetAPZTestData(uint64_t aLayersId, APZTestData* aOutData);

Does anyone use the return value?
Attachment #8954878 - Flags: review?(botond) → review+
(In reply to Botond Ballo [:botond] from comment #38)
> 
> Does anyone use the return value?

I guess not, but I feel it's always a good idea to have a return value for things that produce out-parameters, so that the caller can at least check if the out-param was populated, if it needs to. I could make the call site do that and emit a NS_WARNING or something.
(In reply to Kartikaya Gupta (email:kats@mozilla.com) from comment #39)
> (In reply to Botond Ballo [:botond] from comment #38)
> > 
> > Does anyone use the return value?
> 
> I guess not, but I feel it's always a good idea to have a return value for
> things that produce out-parameters, so that the caller can at least check if
> the out-param was populated, if it needs to. I could make the call site do
> that and emit a NS_WARNING or something.

That's fine, just wanted to make sure it wasn't an oversight.

Comment 41

Last year
Pushed by kgupta@mozilla.com:
https://hg.mozilla.org/integration/autoland/rev/fa85e7327310
Add hooks in APZCTreeManager to respond to layer tree changes. r=botond
https://hg.mozilla.org/integration/autoland/rev/1ecd27281e6b
Replace the code to clear focus targets with the simpler hook. r=botond
https://hg.mozilla.org/integration/autoland/rev/5b0855476e63
Move APZTestData from the LayerTreeState structure into the APZ. r=botond
https://hg.mozilla.org/integration/autoland/rev/243444effec3
Remove calls to GetIndirectShadowTree inside APZCTreeManager. r=botond
https://hg.mozilla.org/integration/autoland/rev/928e83cc6178
Introduce the notion of the APZ sampler thread. r=botond
https://hg.mozilla.org/integration/autoland/rev/5bbb3e69e745
Modify the static GetAPZCTreeManager to return an IAPZCTreeManager. r=botond
https://hg.mozilla.org/integration/autoland/rev/da64726bf399
Introduce an APZSampler interface for APZCTreeManager. r=botond
Depends on: 1443187

Updated

Last year
Depends on: 1447157
You need to log in before you can comment on or make changes to this bug.