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"
18 #include "mozilla/DataMutex.h"
19 #include "mozilla/ThreadSafeWeakPtr.h"
20 #include "nsTHashMap.h"
21 #include "nsTHashSet.h"
22 #include "nsISupportsImpl.h"
27 class DrawTargetRecording
;
30 class DrawEventRecorderPrivate
: public DrawEventRecorder
{
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
{
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());
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();
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
) {
94 void SetDrawTarget(ReferencePtr aDT
);
96 void ClearDrawTarget(DrawTargetRecording
* aDT
) {
97 ReferencePtr dt
= aDT
;
98 if (mCurrentDT
== dt
) {
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);
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
);
166 // Only used within debug assertions.
167 bool HasStoredObject(const ReferencePtr aObject
) {
168 ProcessPendingDeletions();
169 return mStoredObjects
.Contains(aObject
);
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
);
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
) {
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
;
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
{
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
307 virtual ~DrawEventRecorderMemory() = default;
310 SerializeResourcesFn mSerializeCallback
;
311 nsTHashSet
<uint64_t> mDependentSurfaces
;
313 void Flush() override
;
317 } // namespace mozilla
319 #endif /* MOZILLA_GFX_DRAWEVENTRECORDER_H_ */