no bug - Bumping Firefox l10n changesets r=release a=l10n-bump DONTBUILD CLOSED TREE
[gecko.git] / gfx / 2d / DrawEventRecorder.h
blobd62f0987846111bb1901ed3b62e25c6aa5638fdf
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef MOZILLA_GFX_DRAWEVENTRECORDER_H_
8 #define MOZILLA_GFX_DRAWEVENTRECORDER_H_
10 #include "2D.h"
11 #include "RecordedEvent.h"
12 #include "RecordingTypes.h"
14 #include <deque>
15 #include <functional>
16 #include <vector>
18 #include "mozilla/DataMutex.h"
19 #include "mozilla/ThreadSafeWeakPtr.h"
20 #include "nsTHashMap.h"
21 #include "nsTHashSet.h"
22 #include "nsISupportsImpl.h"
24 namespace mozilla {
25 namespace gfx {
27 class DrawTargetRecording;
28 class PathRecording;
30 class DrawEventRecorderPrivate : public DrawEventRecorder {
31 public:
32 MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawEventRecorderPrivate, override)
34 DrawEventRecorderPrivate();
35 virtual ~DrawEventRecorderPrivate();
36 RecorderType GetRecorderType() const override {
37 return RecorderType::PRIVATE;
39 bool Finish() override {
40 ClearResources();
41 return true;
43 virtual void FlushItem(IntRect) {}
44 virtual void DetachResources() {
45 NS_ASSERT_OWNINGTHREAD(DrawEventRecorderPrivate);
47 nsTHashSet<ScaledFont*> fonts = std::move(mStoredFonts);
48 for (const auto& font : fonts) {
49 font->RemoveUserData(reinterpret_cast<UserDataKey*>(this));
52 // SourceSurfaces can be deleted off the main thread, so we use
53 // ThreadSafeWeakPtrs to allow for this. RemoveUserData is thread safe.
54 nsTHashMap<void*, ThreadSafeWeakPtr<SourceSurface>> surfaces =
55 std::move(mStoredSurfaces);
56 for (const auto& entry : surfaces) {
57 RefPtr<SourceSurface> strongRef(entry.GetData());
58 if (strongRef) {
59 strongRef->RemoveUserData(reinterpret_cast<UserDataKey*>(this));
63 // Now that we've detached we can't get any more pending deletions, so
64 // processing now should mean we include all clean up operations.
65 ProcessPendingDeletions();
68 void ClearResources() {
69 NS_ASSERT_OWNINGTHREAD(DrawEventRecorderPrivate);
70 mStoredObjects.Clear();
71 mStoredFontData.Clear();
72 mScaledFonts.clear();
73 mCurrentDT = nullptr;
76 template <class S>
77 void WriteHeader(S& aStream) {
78 NS_ASSERT_OWNINGTHREAD(DrawEventRecorderPrivate);
79 WriteElement(aStream, kMagicInt);
80 WriteElement(aStream, kMajorRevision);
81 WriteElement(aStream, kMinorRevision);
84 virtual void RecordEvent(const RecordedEvent& aEvent) = 0;
86 void RecordEvent(DrawTargetRecording* aDT, const RecordedEvent& aEvent) {
87 ReferencePtr dt = aDT;
88 if (mCurrentDT != dt) {
89 SetDrawTarget(dt);
91 RecordEvent(aEvent);
94 void SetDrawTarget(ReferencePtr aDT);
96 void ClearDrawTarget(DrawTargetRecording* aDT) {
97 ReferencePtr dt = aDT;
98 if (mCurrentDT == dt) {
99 mCurrentDT = nullptr;
103 void AddStoredObject(const ReferencePtr aObject) {
104 ProcessPendingDeletions();
105 mStoredObjects.Insert(aObject);
109 * This is a combination of HasStoredObject and AddStoredObject, so that we
110 * only have to call ProcessPendingDeletions once, which involves locking.
111 * @param aObject the object to store if not already stored
112 * @return true if the object was not already stored, false if it was
114 bool TryAddStoredObject(const ReferencePtr aObject) {
115 ProcessPendingDeletions();
116 return mStoredObjects.EnsureInserted(aObject);
119 virtual void AddPendingDeletion(std::function<void()>&& aPendingDeletion) {
120 auto lockedPendingDeletions = mPendingDeletions.Lock();
121 lockedPendingDeletions->emplace_back(std::move(aPendingDeletion));
124 void RemoveStoredObject(const ReferencePtr aObject) {
125 NS_ASSERT_OWNINGTHREAD(DrawEventRecorderPrivate);
126 mStoredObjects.Remove(aObject);
130 * @param aUnscaledFont the UnscaledFont to increment the reference count for
131 * @return the previous reference count
133 int32_t IncrementUnscaledFontRefCount(const ReferencePtr aUnscaledFont) {
134 NS_ASSERT_OWNINGTHREAD(DrawEventRecorderPrivate);
135 int32_t& count = mUnscaledFontRefs.LookupOrInsert(aUnscaledFont, 0);
136 return count++;
140 * Decrements the reference count for aUnscaledFont and, if count is now zero,
141 * records its destruction.
142 * @param aUnscaledFont the UnscaledFont to decrement the reference count for
144 void DecrementUnscaledFontRefCount(const ReferencePtr aUnscaledFont);
146 void AddScaledFont(ScaledFont* aFont) {
147 NS_ASSERT_OWNINGTHREAD(DrawEventRecorderPrivate);
148 if (mStoredFonts.EnsureInserted(aFont) && WantsExternalFonts()) {
149 mScaledFonts.push_back(aFont);
153 void RemoveScaledFont(ScaledFont* aFont) { mStoredFonts.Remove(aFont); }
155 void AddSourceSurface(SourceSurface* aSurface) {
156 NS_ASSERT_OWNINGTHREAD(DrawEventRecorderPrivate);
157 mStoredSurfaces.InsertOrUpdate(aSurface, aSurface);
160 void RemoveSourceSurface(SourceSurface* aSurface) {
161 NS_ASSERT_OWNINGTHREAD(DrawEventRecorderPrivate);
162 mStoredSurfaces.Remove(aSurface);
165 #if defined(DEBUG)
166 // Only used within debug assertions.
167 bool HasStoredObject(const ReferencePtr aObject) {
168 ProcessPendingDeletions();
169 return mStoredObjects.Contains(aObject);
171 #endif
173 void AddStoredFontData(const uint64_t aFontDataKey) {
174 NS_ASSERT_OWNINGTHREAD(DrawEventRecorderPrivate);
175 mStoredFontData.Insert(aFontDataKey);
178 bool HasStoredFontData(const uint64_t aFontDataKey) {
179 NS_ASSERT_OWNINGTHREAD(DrawEventRecorderPrivate);
180 return mStoredFontData.Contains(aFontDataKey);
183 bool WantsExternalFonts() const { return mExternalFonts; }
185 virtual void StoreSourceSurfaceRecording(SourceSurface* aSurface,
186 const char* aReason);
189 * Used when a source surface is destroyed, aSurface is a void* instead of a
190 * SourceSurface* because this is called during the SourceSurface destructor,
191 * so it is partially destructed and should not be accessed.
192 * @param aSurface the surface whose destruction is being recorded
194 void RecordSourceSurfaceDestruction(void* aSurface);
196 virtual void AddDependentSurface(uint64_t aDependencyId) {
197 MOZ_CRASH("GFX: AddDependentSurface");
200 struct ExternalSurfaceEntry {
201 RefPtr<SourceSurface> mSurface;
202 int64_t mEventCount = -1;
205 using ExternalSurfacesHolder = std::deque<ExternalSurfaceEntry>;
207 void TakeExternalSurfaces(ExternalSurfacesHolder& aSurfaces) {
208 NS_ASSERT_OWNINGTHREAD(DrawEventRecorderPrivate);
209 aSurfaces = std::move(mExternalSurfaces);
212 protected:
213 NS_DECL_OWNINGTHREAD
215 void StoreExternalSurfaceRecording(SourceSurface* aSurface, uint64_t aKey);
217 void ProcessPendingDeletions() {
218 NS_ASSERT_OWNINGTHREAD(DrawEventRecorderPrivate);
220 PendingDeletionsVector pendingDeletions;
222 auto lockedPendingDeletions = mPendingDeletions.Lock();
223 pendingDeletions.swap(*lockedPendingDeletions);
225 for (const auto& pendingDeletion : pendingDeletions) {
226 pendingDeletion();
230 virtual void Flush() = 0;
232 nsTHashSet<const void*> mStoredObjects;
234 using PendingDeletionsVector = std::vector<std::function<void()>>;
235 DataMutex<PendingDeletionsVector> mPendingDeletions{
236 "DrawEventRecorderPrivate::mPendingDeletions"};
238 // It's difficult to track the lifetimes of UnscaledFonts directly, so we
239 // instead track the number of recorded ScaledFonts that hold a reference to
240 // an Unscaled font and use that as a proxy to the real lifetime. An
241 // UnscaledFonts lifetime could be longer than this, but we only use the
242 // ScaledFonts directly and if another uses an UnscaledFont we have destroyed
243 // on the translation side, it will be recreated.
244 nsTHashMap<const void*, int32_t> mUnscaledFontRefs;
246 nsTHashSet<uint64_t> mStoredFontData;
247 nsTHashSet<ScaledFont*> mStoredFonts;
248 std::vector<RefPtr<ScaledFont>> mScaledFonts;
250 // SourceSurfaces can get deleted off the main thread, so we hold a map of the
251 // raw pointer to a ThreadSafeWeakPtr to protect against this.
252 nsTHashMap<void*, ThreadSafeWeakPtr<SourceSurface>> mStoredSurfaces;
254 ReferencePtr mCurrentDT;
255 ExternalSurfacesHolder mExternalSurfaces;
256 bool mExternalFonts;
259 typedef std::function<void(MemStream& aStream,
260 std::vector<RefPtr<ScaledFont>>& aScaledFonts)>
261 SerializeResourcesFn;
263 // WARNING: This should not be used in its existing state because
264 // it is likely to OOM because of large continguous allocations.
265 class DrawEventRecorderMemory : public DrawEventRecorderPrivate {
266 public:
267 MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawEventRecorderMemory, override)
270 * Constructs a DrawEventRecorder that stores the recording in memory.
272 DrawEventRecorderMemory();
273 explicit DrawEventRecorderMemory(const SerializeResourcesFn& aSerialize);
275 RecorderType GetRecorderType() const override { return RecorderType::MEMORY; }
277 void RecordEvent(const RecordedEvent& aEvent) override;
279 void AddDependentSurface(uint64_t aDependencyId) override;
281 nsTHashSet<uint64_t>&& TakeDependentSurfaces();
284 * @return the current size of the recording (in chars).
286 size_t RecordingSize();
289 * Wipes the internal recording buffer, but the recorder does NOT forget which
290 * objects it has recorded. This can be used so that a recording can be copied
291 * and processed in chunks, releasing memory as it goes.
293 void WipeRecording();
294 bool Finish() override;
295 void FlushItem(IntRect) override;
297 MemStream mOutputStream;
298 /* The index stream is of the form:
299 * ItemIndex { size_t dataEnd; size_t extraDataEnd; }
300 * It gets concatenated to the end of mOutputStream in Finish()
301 * The last size_t in the stream is offset of the begining of the
302 * index.
304 MemStream mIndex;
306 protected:
307 virtual ~DrawEventRecorderMemory() = default;
309 private:
310 SerializeResourcesFn mSerializeCallback;
311 nsTHashSet<uint64_t> mDependentSurfaces;
313 void Flush() override;
316 } // namespace gfx
317 } // namespace mozilla
319 #endif /* MOZILLA_GFX_DRAWEVENTRECORDER_H_ */