summaryrefslogtreecommitdiffstats
path: root/gfx/layers/apz/public/APZUpdater.h
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/layers/apz/public/APZUpdater.h')
-rw-r--r--gfx/layers/apz/public/APZUpdater.h236
1 files changed, 236 insertions, 0 deletions
diff --git a/gfx/layers/apz/public/APZUpdater.h b/gfx/layers/apz/public/APZUpdater.h
new file mode 100644
index 0000000000..66d040b356
--- /dev/null
+++ b/gfx/layers/apz/public/APZUpdater.h
@@ -0,0 +1,236 @@
+/* -*- 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;
+
+ /**
+ * 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.
+ */
+ void RunOnUpdaterThread(LayersId aLayersId, already_AddRefed<Runnable> aTask);
+
+ /**
+ * 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