244 lines
10 KiB
C++
244 lines
10 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
/* 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_APZUpdater_h
|
|
#define mozilla_layers_APZUpdater_h
|
|
|
|
#include <deque>
|
|
#include <unordered_map>
|
|
|
|
#include "base/platform_thread.h" // for PlatformThreadId
|
|
#include "LayersTypes.h"
|
|
#include "mozilla/layers/APZTestData.h"
|
|
#include "mozilla/layers/WebRenderScrollData.h"
|
|
#include "mozilla/StaticMutex.h"
|
|
#include "mozilla/StaticPtr.h"
|
|
#include "mozilla/webrender/WebRenderTypes.h"
|
|
#include "nsThreadUtils.h"
|
|
#include "Units.h"
|
|
|
|
namespace mozilla {
|
|
|
|
namespace layers {
|
|
|
|
class APZCTreeManager;
|
|
class FocusTarget;
|
|
class WebRenderScrollData;
|
|
|
|
/**
|
|
* This interface is used to send updates or otherwise mutate APZ internal
|
|
* state. These functions is usually called from the compositor thread in
|
|
* response to IPC messages. The method implementations internally redispatch
|
|
* themselves to the updater thread in the case where the compositor thread
|
|
* is not the updater thread.
|
|
*/
|
|
class APZUpdater {
|
|
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(APZUpdater)
|
|
|
|
public:
|
|
APZUpdater(const RefPtr<APZCTreeManager>& aApz, bool aConnectedToWebRender);
|
|
|
|
bool HasTreeManager(const RefPtr<APZCTreeManager>& aApz);
|
|
void SetWebRenderWindowId(const wr::WindowId& aWindowId);
|
|
|
|
/**
|
|
* This function is invoked from rust on the scene builder thread when it
|
|
* is created. It effectively tells the APZUpdater "the current thread is
|
|
* the updater thread for this window id" and allows APZUpdater to remember
|
|
* which thread it is.
|
|
*/
|
|
static void SetUpdaterThread(const wr::WrWindowId& aWindowId);
|
|
static void PrepareForSceneSwap(const wr::WrWindowId& aWindowId);
|
|
static void CompleteSceneSwap(const wr::WrWindowId& aWindowId,
|
|
const wr::WrPipelineInfo& aInfo);
|
|
static void ProcessPendingTasks(const wr::WrWindowId& aWindowId);
|
|
|
|
void ClearTree(LayersId aRootLayersId);
|
|
void UpdateFocusState(LayersId aRootLayerTreeId,
|
|
LayersId aOriginatingLayersId,
|
|
const FocusTarget& aFocusTarget);
|
|
/**
|
|
* This should be called (in the WR-enabled case) when the compositor receives
|
|
* a new WebRenderScrollData for a layers id. The |aScrollData| parameter is
|
|
* the scroll data for |aOriginatingLayersId| and |aEpoch| is the
|
|
* corresponding epoch for the transaction that transferred the scroll data.
|
|
* This function will store the new scroll data and update the focus state and
|
|
* hit-testing tree.
|
|
*/
|
|
void UpdateScrollDataAndTreeState(LayersId aRootLayerTreeId,
|
|
LayersId aOriginatingLayersId,
|
|
const wr::Epoch& aEpoch,
|
|
WebRenderScrollData&& aScrollData);
|
|
/**
|
|
* This is called in the WR-enabled case when we get an empty transaction that
|
|
* has some scroll offset updates (from paint-skipped scrolling on the content
|
|
* side). This function will update the stored scroll offsets and the
|
|
* hit-testing tree.
|
|
*/
|
|
void UpdateScrollOffsets(LayersId aRootLayerTreeId,
|
|
LayersId aOriginatingLayersId,
|
|
ScrollUpdatesMap&& aUpdates,
|
|
uint32_t aPaintSequenceNumber);
|
|
|
|
void NotifyLayerTreeAdopted(LayersId aLayersId,
|
|
const RefPtr<APZUpdater>& aOldUpdater);
|
|
void NotifyLayerTreeRemoved(LayersId aLayersId);
|
|
|
|
bool GetAPZTestData(LayersId aLayersId, APZTestData* aOutData);
|
|
|
|
void SetTestAsyncScrollOffset(LayersId aLayersId,
|
|
const ScrollableLayerGuid::ViewID& aScrollId,
|
|
const CSSPoint& aOffset);
|
|
void SetTestAsyncZoom(LayersId aLayersId,
|
|
const ScrollableLayerGuid::ViewID& aScrollId,
|
|
const LayerToParentLayerScale& aZoom);
|
|
|
|
// This can only be called on the updater thread.
|
|
const WebRenderScrollData* GetScrollData(LayersId aLayersId) const;
|
|
|
|
/**
|
|
* This can be used to assert that the current thread is the
|
|
* updater thread (which samples the async transform).
|
|
* This does nothing if thread assertions are disabled.
|
|
*/
|
|
void AssertOnUpdaterThread() const;
|
|
|
|
enum class DuringShutdown {
|
|
No,
|
|
Yes,
|
|
};
|
|
/**
|
|
* Runs the given task on the APZ "updater thread" for this APZUpdater. If
|
|
* this function is called from the updater thread itself then the task is
|
|
* run immediately without getting queued.
|
|
*
|
|
* The layers id argument should be the id of the layer tree that is
|
|
* requesting this task to be run. Conceptually each layer tree has a separate
|
|
* task queue, so that if one layer tree is blocked waiting for a scene build
|
|
* then tasks for the other layer trees can still be processed.
|
|
*
|
|
* In the case of where |aDuringShutdown| is `Yes` this function doesn't
|
|
* invoke `WebRenderAPI::WakeSceneBuilder` explicitly.
|
|
*/
|
|
void RunOnUpdaterThread(LayersId aLayersId, already_AddRefed<Runnable> aTask,
|
|
DuringShutdown aDuringShutdown = DuringShutdown::No);
|
|
|
|
/**
|
|
* Returns true if currently on the APZUpdater's "updater thread".
|
|
*/
|
|
bool IsUpdaterThread() const;
|
|
|
|
/**
|
|
* Dispatches the given task to the APZ "controller thread", but does it
|
|
* *from* the updater thread. That is, if the thread on which this function is
|
|
* called is not the updater thread, the task is first dispatched to the
|
|
* updater thread. When the updater thread runs it (or if this is called
|
|
* directly on the updater thread), that is when the task gets dispatched to
|
|
* the controller thread. The controller thread then actually runs the task.
|
|
*
|
|
* See the RunOnUpdaterThread method for details on the layers id argument.
|
|
*/
|
|
void RunOnControllerThread(LayersId aLayersId,
|
|
already_AddRefed<Runnable> aTask);
|
|
|
|
void MarkAsDetached(LayersId aLayersId);
|
|
|
|
protected:
|
|
virtual ~APZUpdater();
|
|
|
|
// Return true if the APZUpdater is connected to WebRender and is
|
|
// using a WebRender scene builder thread as its updater thread.
|
|
// This is only false during GTests, and a shutdown codepath during
|
|
// which we create a dummy APZUpdater.
|
|
bool IsConnectedToWebRender() const;
|
|
|
|
static already_AddRefed<APZUpdater> GetUpdater(
|
|
const wr::WrWindowId& aWindowId);
|
|
|
|
void ProcessQueue();
|
|
|
|
private:
|
|
RefPtr<APZCTreeManager> mApz;
|
|
bool mDestroyed;
|
|
bool mConnectedToWebRender;
|
|
|
|
// Map from layers id to WebRenderScrollData. This can only be touched on
|
|
// the updater thread.
|
|
std::unordered_map<LayersId, WebRenderScrollData, LayersId::HashFn>
|
|
mScrollData;
|
|
|
|
// Stores epoch state for a particular layers id. This structure is only
|
|
// accessed on the updater thread.
|
|
struct EpochState {
|
|
// The epoch for the most recent scroll data sent from the content side.
|
|
wr::Epoch mRequired;
|
|
// The epoch for the most recent scene built and swapped in on the WR side.
|
|
Maybe<wr::Epoch> mBuilt;
|
|
// True if and only if the layers id is the root layers id for the
|
|
// compositor
|
|
bool mIsRoot;
|
|
|
|
EpochState();
|
|
|
|
// Whether or not the state for this layers id is such that it blocks
|
|
// processing of tasks for the layer tree. This happens if the root layers
|
|
// id or a "visible" layers id has scroll data for an epoch newer than what
|
|
// has been built. A "visible" layers id is one that is attached to the full
|
|
// layer tree (i.e. there is a chain of reflayer items from the root layer
|
|
// tree to the relevant layer subtree). This is not always the case; for
|
|
// instance a content process may send the compositor layers for a document
|
|
// before the chrome has attached the remote iframe to the root document.
|
|
// Since WR only builds pipelines for "visible" layers ids, |mBuilt| being
|
|
// populated means that the layers id is "visible".
|
|
bool IsBlocked() const;
|
|
};
|
|
|
|
// Map from layers id to epoch state.
|
|
// This data structure can only be touched on the updater thread.
|
|
std::unordered_map<LayersId, EpochState, LayersId::HashFn> mEpochData;
|
|
|
|
// Used to manage the mapping from a WR window id to APZUpdater. These are
|
|
// only used if WebRender is enabled. Both sWindowIdMap and mWindowId should
|
|
// only be used while holding the sWindowIdLock. Note that we use a
|
|
// StaticAutoPtr wrapper on sWindowIdMap to avoid a static initializer for the
|
|
// unordered_map. This also avoids the initializer/memory allocation in cases
|
|
// where we're not using WebRender.
|
|
static StaticMutex sWindowIdLock MOZ_UNANNOTATED;
|
|
static StaticAutoPtr<std::unordered_map<uint64_t, APZUpdater*>> sWindowIdMap;
|
|
Maybe<wr::WrWindowId> mWindowId;
|
|
|
|
// Lock used to protected mUpdaterThreadId;
|
|
mutable Mutex mThreadIdLock MOZ_UNANNOTATED;
|
|
// If WebRender and async scene building are enabled, this holds the thread id
|
|
// of the scene builder thread (which is the updater thread) for the
|
|
// compositor associated with this APZUpdater instance. It may be populated
|
|
// even if async scene building is not enabled, but in that case we don't
|
|
// care about the contents.
|
|
Maybe<PlatformThreadId> mUpdaterThreadId;
|
|
|
|
// Helper struct that pairs each queued runnable with the layers id that it is
|
|
// associated with. This allows us to easily implement the conceptual
|
|
// separation of mUpdaterQueue into independent queues per layers id.
|
|
struct QueuedTask {
|
|
LayersId mLayersId;
|
|
RefPtr<Runnable> mRunnable;
|
|
};
|
|
|
|
// Lock used to protect mUpdaterQueue
|
|
Mutex mQueueLock MOZ_UNANNOTATED;
|
|
// Holds a queue of tasks to be run on the updater thread, when the updater
|
|
// thread is a WebRender thread, since it won't have a message loop we can
|
|
// dispatch to. Note that although this is a single queue it is conceptually
|
|
// separated into multiple ones, one per layers id. Tasks for a given layers
|
|
// id will always run in FIFO order, but there is no guaranteed ordering for
|
|
// tasks with different layers ids.
|
|
std::deque<QueuedTask> mUpdaterQueue;
|
|
};
|
|
|
|
} // namespace layers
|
|
} // namespace mozilla
|
|
|
|
#endif // mozilla_layers_APZUpdater_h
|