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 "ImageContainer.h"
19 #include "mozilla/DataMutex.h"
20 #include "mozilla/ThreadSafeWeakPtr.h"
21 #include "nsTHashMap.h"
22 #include "nsTHashSet.h"
23 #include "nsISupportsImpl.h"
28 class DrawTargetRecording
;
31 class DrawEventRecorderPrivate
: public DrawEventRecorder
{
33 MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawEventRecorderPrivate
, override
)
35 DrawEventRecorderPrivate();
36 virtual ~DrawEventRecorderPrivate();
37 RecorderType
GetRecorderType() const override
{
38 return RecorderType::PRIVATE
;
40 bool Finish() override
{
44 virtual void FlushItem(IntRect
) {}
45 virtual void DetachResources() {
46 NS_ASSERT_OWNINGTHREAD(DrawEventRecorderPrivate
);
48 nsTHashSet
<ScaledFont
*> fonts
= std::move(mStoredFonts
);
49 for (const auto& font
: fonts
) {
50 font
->RemoveUserData(reinterpret_cast<UserDataKey
*>(this));
53 // SourceSurfaces can be deleted off the main thread, so we use
54 // ThreadSafeWeakPtrs to allow for this. RemoveUserData is thread safe.
55 nsTHashMap
<void*, ThreadSafeWeakPtr
<SourceSurface
>> surfaces
=
56 std::move(mStoredSurfaces
);
57 for (const auto& entry
: surfaces
) {
58 RefPtr
<SourceSurface
> strongRef(entry
.GetData());
60 strongRef
->RemoveUserData(reinterpret_cast<UserDataKey
*>(this));
64 // Now that we've detached we can't get any more pending deletions, so
65 // processing now should mean we include all clean up operations.
66 ProcessPendingDeletions();
69 void ClearResources() {
70 NS_ASSERT_OWNINGTHREAD(DrawEventRecorderPrivate
);
71 mStoredObjects
.Clear();
72 mStoredFontData
.Clear();
78 void WriteHeader(S
& aStream
) {
79 NS_ASSERT_OWNINGTHREAD(DrawEventRecorderPrivate
);
80 WriteElement(aStream
, kMagicInt
);
81 WriteElement(aStream
, kMajorRevision
);
82 WriteElement(aStream
, kMinorRevision
);
85 virtual void RecordEvent(const RecordedEvent
& aEvent
) = 0;
87 void RecordEvent(const DrawTargetRecording
* aDT
,
88 const RecordedEvent
& aEvent
) {
89 ReferencePtr dt
= aDT
;
90 if (mCurrentDT
!= dt
) {
96 void SetDrawTarget(ReferencePtr aDT
);
98 void ClearDrawTarget(const DrawTargetRecording
* aDT
) {
99 ReferencePtr dt
= aDT
;
100 if (mCurrentDT
== dt
) {
101 mCurrentDT
= nullptr;
105 void AddStoredObject(const ReferencePtr aObject
) {
106 ProcessPendingDeletions();
107 mStoredObjects
.Insert(aObject
);
111 * This is a combination of HasStoredObject and AddStoredObject, so that we
112 * only have to call ProcessPendingDeletions once, which involves locking.
113 * @param aObject the object to store if not already stored
114 * @return true if the object was not already stored, false if it was
116 bool TryAddStoredObject(const ReferencePtr aObject
) {
117 ProcessPendingDeletions();
118 return mStoredObjects
.EnsureInserted(aObject
);
121 virtual void AddPendingDeletion(std::function
<void()>&& aPendingDeletion
) {
122 auto lockedPendingDeletions
= mPendingDeletions
.Lock();
123 lockedPendingDeletions
->emplace_back(std::move(aPendingDeletion
));
126 void RemoveStoredObject(const ReferencePtr aObject
) {
127 NS_ASSERT_OWNINGTHREAD(DrawEventRecorderPrivate
);
128 mStoredObjects
.Remove(aObject
);
132 * @param aUnscaledFont the UnscaledFont to increment the reference count for
133 * @return the previous reference count
135 int32_t IncrementUnscaledFontRefCount(const ReferencePtr aUnscaledFont
) {
136 NS_ASSERT_OWNINGTHREAD(DrawEventRecorderPrivate
);
137 int32_t& count
= mUnscaledFontRefs
.LookupOrInsert(aUnscaledFont
, 0);
142 * Decrements the reference count for aUnscaledFont and, if count is now zero,
143 * records its destruction.
144 * @param aUnscaledFont the UnscaledFont to decrement the reference count for
146 void DecrementUnscaledFontRefCount(const ReferencePtr aUnscaledFont
);
148 void AddScaledFont(ScaledFont
* aFont
) {
149 NS_ASSERT_OWNINGTHREAD(DrawEventRecorderPrivate
);
150 if (mStoredFonts
.EnsureInserted(aFont
) && WantsExternalFonts()) {
151 mScaledFonts
.push_back(aFont
);
155 void RemoveScaledFont(ScaledFont
* aFont
) { mStoredFonts
.Remove(aFont
); }
157 void AddSourceSurface(SourceSurface
* aSurface
) {
158 NS_ASSERT_OWNINGTHREAD(DrawEventRecorderPrivate
);
159 mStoredSurfaces
.InsertOrUpdate(aSurface
, aSurface
);
162 void RemoveSourceSurface(SourceSurface
* aSurface
) {
163 NS_ASSERT_OWNINGTHREAD(DrawEventRecorderPrivate
);
164 mStoredSurfaces
.Remove(aSurface
);
168 // Only used within debug assertions.
169 bool HasStoredObject(const ReferencePtr aObject
) {
170 ProcessPendingDeletions();
171 return mStoredObjects
.Contains(aObject
);
175 void AddStoredFontData(const uint64_t aFontDataKey
) {
176 NS_ASSERT_OWNINGTHREAD(DrawEventRecorderPrivate
);
177 mStoredFontData
.Insert(aFontDataKey
);
180 bool HasStoredFontData(const uint64_t aFontDataKey
) {
181 NS_ASSERT_OWNINGTHREAD(DrawEventRecorderPrivate
);
182 return mStoredFontData
.Contains(aFontDataKey
);
185 bool WantsExternalFonts() const { return mExternalFonts
; }
187 virtual void StoreSourceSurfaceRecording(SourceSurface
* aSurface
,
188 const char* aReason
);
190 virtual void StoreImageRecording(
191 const RefPtr
<layers::Image
>& aImageOfSurfaceDescriptor
,
192 const char* aReasony
) {
193 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
197 * Used when a source surface is destroyed, aSurface is a void* instead of a
198 * SourceSurface* because this is called during the SourceSurface destructor,
199 * so it is partially destructed and should not be accessed.
200 * @param aSurface the surface whose destruction is being recorded
202 void RecordSourceSurfaceDestruction(void* aSurface
);
204 virtual void AddDependentSurface(uint64_t aDependencyId
) {
205 MOZ_CRASH("GFX: AddDependentSurface");
208 struct ExternalSurfaceEntry
{
209 RefPtr
<SourceSurface
> mSurface
;
210 int64_t mEventCount
= -1;
213 using ExternalSurfacesHolder
= std::deque
<ExternalSurfaceEntry
>;
215 void TakeExternalSurfaces(ExternalSurfacesHolder
& aSurfaces
) {
216 NS_ASSERT_OWNINGTHREAD(DrawEventRecorderPrivate
);
217 aSurfaces
= std::move(mExternalSurfaces
);
220 struct ExternalImageEntry
{
221 RefPtr
<layers::Image
> mImage
;
222 int64_t mEventCount
= -1;
225 using ExternalImagesHolder
= std::deque
<ExternalImageEntry
>;
230 void StoreExternalSurfaceRecording(SourceSurface
* aSurface
, uint64_t aKey
);
232 void StoreExternalImageRecording(
233 const RefPtr
<layers::Image
>& aImageOfSurfaceDescriptor
);
235 void ProcessPendingDeletions() {
236 NS_ASSERT_OWNINGTHREAD(DrawEventRecorderPrivate
);
238 PendingDeletionsVector pendingDeletions
;
240 auto lockedPendingDeletions
= mPendingDeletions
.Lock();
241 pendingDeletions
.swap(*lockedPendingDeletions
);
243 for (const auto& pendingDeletion
: pendingDeletions
) {
248 virtual void Flush() = 0;
250 nsTHashSet
<const void*> mStoredObjects
;
252 using PendingDeletionsVector
= std::vector
<std::function
<void()>>;
253 DataMutex
<PendingDeletionsVector
> mPendingDeletions
{
254 "DrawEventRecorderPrivate::mPendingDeletions"};
256 // It's difficult to track the lifetimes of UnscaledFonts directly, so we
257 // instead track the number of recorded ScaledFonts that hold a reference to
258 // an Unscaled font and use that as a proxy to the real lifetime. An
259 // UnscaledFonts lifetime could be longer than this, but we only use the
260 // ScaledFonts directly and if another uses an UnscaledFont we have destroyed
261 // on the translation side, it will be recreated.
262 nsTHashMap
<const void*, int32_t> mUnscaledFontRefs
;
264 nsTHashSet
<uint64_t> mStoredFontData
;
265 nsTHashSet
<ScaledFont
*> mStoredFonts
;
266 std::vector
<RefPtr
<ScaledFont
>> mScaledFonts
;
268 // SourceSurfaces can get deleted off the main thread, so we hold a map of the
269 // raw pointer to a ThreadSafeWeakPtr to protect against this.
270 nsTHashMap
<void*, ThreadSafeWeakPtr
<SourceSurface
>> mStoredSurfaces
;
272 ReferencePtr mCurrentDT
;
273 ExternalSurfacesHolder mExternalSurfaces
;
274 ExternalImagesHolder mExternalImages
;
278 typedef std::function
<void(MemStream
& aStream
,
279 std::vector
<RefPtr
<ScaledFont
>>& aScaledFonts
)>
280 SerializeResourcesFn
;
282 // WARNING: This should not be used in its existing state because
283 // it is likely to OOM because of large continguous allocations.
284 class DrawEventRecorderMemory
: public DrawEventRecorderPrivate
{
286 MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawEventRecorderMemory
, override
)
289 * Constructs a DrawEventRecorder that stores the recording in memory.
291 DrawEventRecorderMemory();
292 explicit DrawEventRecorderMemory(const SerializeResourcesFn
& aSerialize
);
294 RecorderType
GetRecorderType() const override
{ return RecorderType::MEMORY
; }
296 void RecordEvent(const RecordedEvent
& aEvent
) override
;
298 void AddDependentSurface(uint64_t aDependencyId
) override
;
300 nsTHashSet
<uint64_t>&& TakeDependentSurfaces();
303 * @return the current size of the recording (in chars).
305 size_t RecordingSize();
308 * Wipes the internal recording buffer, but the recorder does NOT forget which
309 * objects it has recorded. This can be used so that a recording can be copied
310 * and processed in chunks, releasing memory as it goes.
312 void WipeRecording();
313 bool Finish() override
;
314 void FlushItem(IntRect
) override
;
316 MemStream mOutputStream
;
317 /* The index stream is of the form:
318 * ItemIndex { size_t dataEnd; size_t extraDataEnd; }
319 * It gets concatenated to the end of mOutputStream in Finish()
320 * The last size_t in the stream is offset of the begining of the
326 virtual ~DrawEventRecorderMemory() = default;
329 SerializeResourcesFn mSerializeCallback
;
330 nsTHashSet
<uint64_t> mDependentSurfaces
;
332 void Flush() override
;
336 } // namespace mozilla
338 #endif /* MOZILLA_GFX_DRAWEVENTRECORDER_H_ */