1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #ifndef DisplayItemList_h
6 #define DisplayItemList_h
8 #include "platform/PlatformExport.h"
9 #include "platform/RuntimeEnabledFeatures.h"
10 #include "platform/geometry/LayoutPoint.h"
11 #include "platform/graphics/ContiguousContainer.h"
12 #include "platform/graphics/paint/DisplayItem.h"
13 #include "platform/graphics/paint/Transform3DDisplayItem.h"
14 #include "wtf/Alignment.h"
15 #include "wtf/HashMap.h"
16 #include "wtf/PassOwnPtr.h"
17 #include "wtf/Utility.h"
18 #include "wtf/Vector.h"
22 class GraphicsContext
;
24 // kDisplayItemAlignment must be a multiple of alignof(derived display item) for
25 // each derived display item; the ideal value is the least common multiple.
26 // Currently the limiting factor is TransformtionMatrix (in
27 // BeginTransform3DDisplayItem), which requests 16-byte alignment.
28 static const size_t kDisplayItemAlignment
= WTF_ALIGN_OF(BeginTransform3DDisplayItem
);
29 static const size_t kInitialDisplayItemsCapacity
= 64;
30 static const size_t kMaximumDisplayItemSize
= sizeof(BeginTransform3DDisplayItem
);
32 // Map from SimpleLayer.startPoint to the DrawingDisplayItems within its range
33 // which were invalidated on this frame and do not change SimpleLayers.
34 using DisplayListDiff
= HashMap
<DisplayItemClient
, DisplayItem
*>;
36 class DisplayItems
: public ContiguousContainer
<DisplayItem
, kDisplayItemAlignment
> {
38 DisplayItems(size_t initialSizeBytes
)
39 : ContiguousContainer(kMaximumDisplayItemSize
, initialSizeBytes
) {}
41 DisplayItem
& appendByMoving(DisplayItem
& item
)
44 WTF::String originalDebugString
= item
.asDebugString();
46 ASSERT(item
.isValid());
47 DisplayItem
& result
= ContiguousContainer::appendByMoving(item
, item
.derivedSize());
48 // ContiguousContainer::appendByMoving() called in-place constructor on item, which invalidated it.
49 ASSERT(!item
.isValid());
51 // Save original debug string in the old item to help debugging.
52 item
.setClientDebugString(originalDebugString
);
58 class PLATFORM_EXPORT DisplayItemList
{
59 WTF_MAKE_NONCOPYABLE(DisplayItemList
);
60 WTF_MAKE_FAST_ALLOCATED(DisplayItemList
);
62 static PassOwnPtr
<DisplayItemList
> create()
64 return adoptPtr(new DisplayItemList());
67 // These methods are called during paint invalidation.
68 void invalidate(const DisplayItemClientWrapper
&);
69 void invalidateUntracked(DisplayItemClient
);
72 // Record when paint offsets change during paint.
73 void invalidatePaintOffset(const DisplayItemClientWrapper
&);
75 bool paintOffsetWasInvalidated(DisplayItemClient
) const;
78 // Record a new paint offset.
79 // TODO(pdr): Remove these once the paint offset cache is on LayoutObject.
80 void recordPaintOffset(DisplayItemClient
, const LayoutPoint
&);
81 bool paintOffsetIsUnchanged(DisplayItemClient
, const LayoutPoint
&) const;
83 // These methods are called during painting.
84 template <typename DisplayItemClass
, typename
... Args
>
85 DisplayItemClass
& createAndAppend(Args
&&... args
)
87 static_assert(WTF::IsSubclass
<DisplayItemClass
, DisplayItem
>::value
,
88 "Can only createAndAppend subclasses of DisplayItem.");
89 static_assert(sizeof(DisplayItemClass
) <= kMaximumDisplayItemSize
,
90 "DisplayItem subclass is larger than kMaximumDisplayItemSize.");
92 DisplayItemClass
& displayItem
= m_newDisplayItems
.allocateAndConstruct
<DisplayItemClass
>(WTF::forward
<Args
>(args
)...);
93 processNewItem(displayItem
);
97 // Scopes must be used to avoid duplicated display item ids when we paint some object
98 // multiple times and generate multiple display items with the same type.
99 // We don't cache display items added in scopes.
103 // True if the last display item is a begin that doesn't draw content.
104 bool lastDisplayItemIsNoopBegin() const;
105 void removeLastDisplayItem();
107 void beginSkippingCache() { ++m_skippingCacheCount
; }
108 void endSkippingCache() { ASSERT(m_skippingCacheCount
> 0); --m_skippingCacheCount
; }
109 bool skippingCache() const { return m_skippingCacheCount
; }
111 // Must be called when a painting is finished. If passed, a DisplayListDiff
112 // is initialized and created.
113 void commitNewDisplayItems(DisplayListDiff
* = 0);
115 // Returns the approximate memory usage, excluding memory likely to be
116 // shared with the embedder after copying to WebDisplayItemList.
117 // Should only be called right after commitNewDisplayItems.
118 size_t approximateUnsharedMemoryUsage() const;
120 // Get the paint list generated after the last painting.
121 const DisplayItems
& displayItems() const;
123 bool clientCacheIsValid(DisplayItemClient
) const;
125 // Commits the new display items and plays back the updated display items into the given context.
126 void commitNewDisplayItemsAndReplay(GraphicsContext
& context
)
128 commitNewDisplayItems();
132 void appendToWebDisplayItemList(WebDisplayItemList
*);
133 void commitNewDisplayItemsAndAppendToWebDisplayItemList(WebDisplayItemList
*);
135 bool displayItemConstructionIsDisabled() const { return m_constructionDisabled
; }
136 void setDisplayItemConstructionIsDisabled(const bool disable
) { m_constructionDisabled
= disable
; }
138 // Returns displayItems added using createAndAppend() since beginning or the last
139 // commitNewDisplayItems(). Use with care.
140 DisplayItems
& newDisplayItems() { return m_newDisplayItems
; }
143 void showDebugData() const;
146 void startTrackingPaintInvalidationObjects()
148 ASSERT(RuntimeEnabledFeatures::slimmingPaintV2Enabled());
149 m_trackedPaintInvalidationObjects
= adoptPtr(new Vector
<String
>());
151 void stopTrackingPaintInvalidationObjects()
153 ASSERT(RuntimeEnabledFeatures::slimmingPaintV2Enabled());
154 m_trackedPaintInvalidationObjects
= nullptr;
156 Vector
<String
> trackedPaintInvalidationObjects()
158 ASSERT(RuntimeEnabledFeatures::slimmingPaintV2Enabled());
159 return m_trackedPaintInvalidationObjects
? *m_trackedPaintInvalidationObjects
: Vector
<String
>();
164 : m_currentDisplayItems(0)
165 , m_newDisplayItems(kInitialDisplayItemsCapacity
* kMaximumDisplayItemSize
)
166 , m_validlyCachedClientsDirty(false)
167 , m_constructionDisabled(false)
168 , m_skippingCacheCount(0)
169 , m_numCachedItems(0)
173 // Set new item state (scopes, cache skipping, etc) for a new item.
174 void processNewItem(DisplayItem
&);
176 void updateValidlyCachedClientsIfNeeded() const;
178 // Update the recorded paint offsets to remove any items that no longer have
179 // corresponding cached display items.
180 // TODO(pdr): Remove this once the paint offset cache is on LayoutObject.
181 void removeUnneededPaintOffsetEntries();
184 WTF::String
displayItemsAsDebugString(const DisplayItems
&) const;
187 // Indices into PaintList of all DrawingDisplayItems and BeginSubsequenceDisplayItems of each client.
188 // Temporarily used during merge to find out-of-order display items.
189 using DisplayItemIndicesByClientMap
= HashMap
<DisplayItemClient
, Vector
<size_t>>;
191 static size_t findMatchingItemFromIndex(const DisplayItem::Id
&, const DisplayItemIndicesByClientMap
&, const DisplayItems
&);
192 static void addItemToIndexIfNeeded(const DisplayItem
&, size_t index
, DisplayItemIndicesByClientMap
&);
194 struct OutOfOrderIndexContext
;
195 DisplayItems::iterator
findOutOfOrderCachedItem(const DisplayItem::Id
&, OutOfOrderIndexContext
&);
196 DisplayItems::iterator
findOutOfOrderCachedItemForward(const DisplayItem::Id
&, OutOfOrderIndexContext
&);
197 void copyCachedSubsequence(DisplayItems::iterator
& currentIt
, DisplayItems
& updatedList
);
200 // The following two methods are for checking under-invalidations
201 // (when RuntimeEnabledFeatures::slimmingPaintUnderInvalidationCheckingEnabled).
202 void checkUnderInvalidation(DisplayItems::iterator
& newIt
, DisplayItems::iterator
& currentIt
);
203 void checkCachedDisplayItemIsUnchanged(const char* messagePrefix
, const DisplayItem
& newItem
, const DisplayItem
& oldItem
);
204 void checkNoRemainingCachedDisplayItems();
207 void replay(GraphicsContext
&);
209 DisplayItems m_currentDisplayItems
;
210 DisplayItems m_newDisplayItems
;
212 // Contains all clients having valid cached paintings if updated.
213 // It's lazily updated in updateValidlyCachedClientsIfNeeded().
214 // FIXME: In the future we can replace this with client-side repaint flags
215 // to avoid the cost of building and querying the hash table.
216 mutable HashSet
<DisplayItemClient
> m_validlyCachedClients
;
217 mutable bool m_validlyCachedClientsDirty
;
220 // Set of clients which had paint offset changes since the last commit. This is used for
221 // ensuring paint offsets are only updated once and are the same in all phases.
222 HashSet
<DisplayItemClient
> m_clientsWithPaintOffsetInvalidations
;
225 // Allow display item construction to be disabled to isolate the costs of construction
226 // in performance metrics.
227 bool m_constructionDisabled
;
229 int m_skippingCacheCount
;
231 int m_numCachedItems
;
233 unsigned m_nextScope
;
234 Vector
<unsigned> m_scopeStack
;
236 // Cache of LayoutObject paint offsets.
237 // TODO(pdr): This should be on LayoutObject itself and is only on the display
238 // item list temporarily until paint invalidation for v2 frees up space on
240 using PreviousPaintOffsets
= HashMap
<DisplayItemClient
, LayoutPoint
>;
241 PreviousPaintOffsets m_previousPaintOffsets
;
244 // This is used to check duplicated ids during add(). We could also check during
245 // updatePaintList(), but checking during add() helps developer easily find where
246 // the duplicated ids are from.
247 DisplayItemIndicesByClientMap m_newDisplayItemIndicesByClient
;
250 OwnPtr
<Vector
<String
>> m_trackedPaintInvalidationObjects
;
255 #endif // DisplayItemList_h