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_
11 #include "RecordedEvent.h"
12 #include "RecordingTypes.h"
17 #include "mozilla/DataMutex.h"
18 #include "mozilla/ThreadSafeWeakPtr.h"
19 #include "nsTHashMap.h"
20 #include "nsTHashSet.h"
21 #include "nsISupportsImpl.h"
28 class DrawEventRecorderPrivate
: public DrawEventRecorder
{
30 MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawEventRecorderPrivate
, override
)
32 DrawEventRecorderPrivate();
33 virtual ~DrawEventRecorderPrivate();
34 bool Finish() override
{
38 virtual void FlushItem(IntRect
) {}
39 void DetachResources() {
40 NS_ASSERT_OWNINGTHREAD(DrawEventRecorderPrivate
);
42 nsTHashSet
<ScaledFont
*> fonts
= std::move(mStoredFonts
);
43 for (const auto& font
: fonts
) {
44 font
->RemoveUserData(reinterpret_cast<UserDataKey
*>(this));
47 // SourceSurfaces can be deleted off the main thread, so we use
48 // ThreadSafeWeakPtrs to allow for this. RemoveUserData is thread safe.
49 nsTHashMap
<void*, ThreadSafeWeakPtr
<SourceSurface
>> surfaces
=
50 std::move(mStoredSurfaces
);
51 for (const auto& entry
: surfaces
) {
52 RefPtr
<SourceSurface
> strongRef(entry
.GetData());
54 strongRef
->RemoveUserData(reinterpret_cast<UserDataKey
*>(this));
58 // Now that we've detached we can't get any more pending deletions, so
59 // processing now should mean we include all clean up operations.
60 ProcessPendingDeletions();
63 void ClearResources() {
64 NS_ASSERT_OWNINGTHREAD(DrawEventRecorderPrivate
);
65 mStoredObjects
.Clear();
66 mStoredFontData
.Clear();
71 void WriteHeader(S
& aStream
) {
72 NS_ASSERT_OWNINGTHREAD(DrawEventRecorderPrivate
);
73 WriteElement(aStream
, kMagicInt
);
74 WriteElement(aStream
, kMajorRevision
);
75 WriteElement(aStream
, kMinorRevision
);
78 virtual void RecordEvent(const RecordedEvent
& aEvent
) = 0;
80 void AddStoredObject(const ReferencePtr aObject
) {
81 ProcessPendingDeletions();
82 mStoredObjects
.Insert(aObject
);
86 * This is a combination of HasStoredObject and AddStoredObject, so that we
87 * only have to call ProcessPendingDeletions once, which involves locking.
88 * @param aObject the object to store if not already stored
89 * @return true if the object was not already stored, false if it was
91 bool TryAddStoredObject(const ReferencePtr aObject
) {
92 ProcessPendingDeletions();
93 return mStoredObjects
.EnsureInserted(aObject
);
96 void AddPendingDeletion(std::function
<void()>&& aPendingDeletion
) {
97 auto lockedPendingDeletions
= mPendingDeletions
.Lock();
98 lockedPendingDeletions
->emplace_back(std::move(aPendingDeletion
));
101 void RemoveStoredObject(const ReferencePtr aObject
) {
102 NS_ASSERT_OWNINGTHREAD(DrawEventRecorderPrivate
);
103 mStoredObjects
.Remove(aObject
);
107 * @param aUnscaledFont the UnscaledFont to increment the reference count for
108 * @return the previous reference count
110 int32_t IncrementUnscaledFontRefCount(const ReferencePtr aUnscaledFont
) {
111 NS_ASSERT_OWNINGTHREAD(DrawEventRecorderPrivate
);
112 int32_t& count
= mUnscaledFontRefs
.LookupOrInsert(aUnscaledFont
, 0);
117 * Decrements the reference count for aUnscaledFont and, if count is now zero,
118 * records its destruction.
119 * @param aUnscaledFont the UnscaledFont to decrement the reference count for
121 void DecrementUnscaledFontRefCount(const ReferencePtr aUnscaledFont
);
123 void AddScaledFont(ScaledFont
* aFont
) {
124 NS_ASSERT_OWNINGTHREAD(DrawEventRecorderPrivate
);
125 if (mStoredFonts
.EnsureInserted(aFont
) && WantsExternalFonts()) {
126 mScaledFonts
.push_back(aFont
);
130 void RemoveScaledFont(ScaledFont
* aFont
) { mStoredFonts
.Remove(aFont
); }
132 void AddSourceSurface(SourceSurface
* aSurface
) {
133 NS_ASSERT_OWNINGTHREAD(DrawEventRecorderPrivate
);
134 mStoredSurfaces
.InsertOrUpdate(aSurface
, aSurface
);
137 void RemoveSourceSurface(SourceSurface
* aSurface
) {
138 NS_ASSERT_OWNINGTHREAD(DrawEventRecorderPrivate
);
139 mStoredSurfaces
.Remove(aSurface
);
143 // Only used within debug assertions.
144 bool HasStoredObject(const ReferencePtr aObject
) {
145 ProcessPendingDeletions();
146 return mStoredObjects
.Contains(aObject
);
150 void AddStoredFontData(const uint64_t aFontDataKey
) {
151 NS_ASSERT_OWNINGTHREAD(DrawEventRecorderPrivate
);
152 mStoredFontData
.Insert(aFontDataKey
);
155 bool HasStoredFontData(const uint64_t aFontDataKey
) {
156 NS_ASSERT_OWNINGTHREAD(DrawEventRecorderPrivate
);
157 return mStoredFontData
.Contains(aFontDataKey
);
160 bool WantsExternalFonts() const { return mExternalFonts
; }
162 void TakeExternalSurfaces(std::vector
<RefPtr
<SourceSurface
>>& aSurfaces
) {
163 NS_ASSERT_OWNINGTHREAD(DrawEventRecorderPrivate
);
164 aSurfaces
= std::move(mExternalSurfaces
);
167 virtual void StoreSourceSurfaceRecording(SourceSurface
* aSurface
,
168 const char* aReason
);
171 * Used when a source surface is destroyed, aSurface is a void* instead of a
172 * SourceSurface* because this is called during the SourceSurface destructor,
173 * so it is partially destructed and should not be accessed.
174 * @param aSurface the surface whose destruction is being recorded
176 void RecordSourceSurfaceDestruction(void* aSurface
);
178 virtual void AddDependentSurface(uint64_t aDependencyId
) {
179 MOZ_CRASH("GFX: AddDependentSurface");
185 void StoreExternalSurfaceRecording(SourceSurface
* aSurface
, uint64_t aKey
);
187 void ProcessPendingDeletions() {
188 NS_ASSERT_OWNINGTHREAD(DrawEventRecorderPrivate
);
190 PendingDeletionsVector pendingDeletions
;
192 auto lockedPendingDeletions
= mPendingDeletions
.Lock();
193 pendingDeletions
.swap(*lockedPendingDeletions
);
195 for (const auto& pendingDeletion
: pendingDeletions
) {
200 virtual void Flush() = 0;
202 nsTHashSet
<const void*> mStoredObjects
;
204 using PendingDeletionsVector
= std::vector
<std::function
<void()>>;
205 DataMutex
<PendingDeletionsVector
> mPendingDeletions
{
206 "DrawEventRecorderPrivate::mPendingDeletions"};
208 // It's difficult to track the lifetimes of UnscaledFonts directly, so we
209 // instead track the number of recorded ScaledFonts that hold a reference to
210 // an Unscaled font and use that as a proxy to the real lifetime. An
211 // UnscaledFonts lifetime could be longer than this, but we only use the
212 // ScaledFonts directly and if another uses an UnscaledFont we have destroyed
213 // on the translation side, it will be recreated.
214 nsTHashMap
<const void*, int32_t> mUnscaledFontRefs
;
216 nsTHashSet
<uint64_t> mStoredFontData
;
217 nsTHashSet
<ScaledFont
*> mStoredFonts
;
218 std::vector
<RefPtr
<ScaledFont
>> mScaledFonts
;
220 // SourceSurfaces can get deleted off the main thread, so we hold a map of the
221 // raw pointer to a ThreadSafeWeakPtr to protect against this.
222 nsTHashMap
<void*, ThreadSafeWeakPtr
<SourceSurface
>> mStoredSurfaces
;
223 std::vector
<RefPtr
<SourceSurface
>> mExternalSurfaces
;
227 typedef std::function
<void(MemStream
& aStream
,
228 std::vector
<RefPtr
<ScaledFont
>>& aScaledFonts
)>
229 SerializeResourcesFn
;
231 // WARNING: This should not be used in its existing state because
232 // it is likely to OOM because of large continguous allocations.
233 class DrawEventRecorderMemory
: public DrawEventRecorderPrivate
{
235 MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawEventRecorderMemory
, override
)
238 * Constructs a DrawEventRecorder that stores the recording in memory.
240 DrawEventRecorderMemory();
241 explicit DrawEventRecorderMemory(const SerializeResourcesFn
& aSerialize
);
243 void RecordEvent(const RecordedEvent
& aEvent
) override
;
245 void AddDependentSurface(uint64_t aDependencyId
) override
;
247 nsTHashSet
<uint64_t>&& TakeDependentSurfaces();
250 * @return the current size of the recording (in chars).
252 size_t RecordingSize();
255 * Wipes the internal recording buffer, but the recorder does NOT forget which
256 * objects it has recorded. This can be used so that a recording can be copied
257 * and processed in chunks, releasing memory as it goes.
259 void WipeRecording();
260 bool Finish() override
;
261 void FlushItem(IntRect
) override
;
263 MemStream mOutputStream
;
264 /* The index stream is of the form:
265 * ItemIndex { size_t dataEnd; size_t extraDataEnd; }
266 * It gets concatenated to the end of mOutputStream in Finish()
267 * The last size_t in the stream is offset of the begining of the
273 virtual ~DrawEventRecorderMemory() = default;
276 SerializeResourcesFn mSerializeCallback
;
277 nsTHashSet
<uint64_t> mDependentSurfaces
;
279 void Flush() override
;
283 } // namespace mozilla
285 #endif /* MOZILLA_GFX_DRAWEVENTRECORDER_H_ */