Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(174)

Side by Side Diff: third_party/WebKit/Source/platform/graphics/paint/PaintController.cpp

Issue 2107103002: Find cached display items directly during painting (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "platform/graphics/paint/PaintController.h" 5 #include "platform/graphics/paint/PaintController.h"
6 6
7 #include "platform/TraceEvent.h" 7 #include "platform/TraceEvent.h"
8 #include "platform/graphics/GraphicsLayer.h" 8 #include "platform/graphics/GraphicsLayer.h"
9 #include "platform/graphics/paint/DrawingDisplayItem.h" 9 #include "platform/graphics/paint/DrawingDisplayItem.h"
10 #include "third_party/skia/include/core/SkPictureAnalyzer.h" 10 #include "third_party/skia/include/core/SkPictureAnalyzer.h"
(...skipping 13 matching lines...) Expand all
24 return PaintChunker::DefaultBehavior; 24 return PaintChunker::DefaultBehavior;
25 } 25 }
26 26
27 const PaintArtifact& PaintController::paintArtifact() const 27 const PaintArtifact& PaintController::paintArtifact() const
28 { 28 {
29 DCHECK(m_newDisplayItemList.isEmpty()); 29 DCHECK(m_newDisplayItemList.isEmpty());
30 DCHECK(m_newPaintChunks.isInInitialState()); 30 DCHECK(m_newPaintChunks.isInInitialState());
31 return m_currentPaintArtifact; 31 return m_currentPaintArtifact;
32 } 32 }
33 33
34 bool PaintController::useCachedDrawingIfPossible(const DisplayItemClient& client , DisplayItem::Type type)
35 {
36 DCHECK(DisplayItem::isDrawingType(type));
37
38 if (displayItemConstructionIsDisabled())
39 return false;
40
41 if (!clientCacheIsValid(client))
42 return false;
43
44 #if ENABLE(ASSERT)
45 // When under-invalidation checking is enabled, we output CachedDrawing disp lay item
46 // followed by the display item containing forced painting.
47 if (RuntimeEnabledFeatures::slimmingPaintUnderInvalidationCheckingEnabled())
48 return false;
49 #endif
50
51 DisplayItemList::iterator it = findCachedItem(DisplayItem::Id(client, type)) ;
52 if (it == m_currentPaintArtifact.getDisplayItemList().end()) {
53 NOTREACHED();
54 return false;
55 }
56
57 ++m_numCachedNewItems;
58 ensureNewDisplayItemListInitialCapacity();
59 processNewItem(m_newDisplayItemList.appendByMoving(*it));
60
61 m_nextItemToMatch = it + 1;
62 // Items before m_nextItemToMatch have been copied so we don't need to index them.
63 if (m_nextItemToMatch - m_nextItemToIndex > 0)
64 m_nextItemToIndex = m_nextItemToMatch;
65
66 return true;
67 }
68
69 bool PaintController::useCachedSubsequenceIfPossible(const DisplayItemClient& cl ient)
70 {
71 if (displayItemConstructionIsDisabled() || subsequenceCachingIsDisabled())
72 return false;
73
74 if (!clientCacheIsValid(client))
75 return false;
76
77 #if ENABLE(ASSERT)
78 // When under-invalidation checking is enabled, we output CachedDrawing disp lay item
79 // followed by the display item containing forced painting.
80 if (RuntimeEnabledFeatures::slimmingPaintUnderInvalidationCheckingEnabled())
81 return false;
82 #endif
83
84 DisplayItemList::iterator it = findCachedItem(DisplayItem::Id(client, Displa yItem::Subsequence));
85 if (it == m_currentPaintArtifact.getDisplayItemList().end()) {
86 NOTREACHED();
87 return false;
88 }
89
90 // |it| will point to the first item after the subsequence or end of the cur rent list.
91 ensureNewDisplayItemListInitialCapacity();
92 copyCachedSubsequence(it);
93
94 m_nextItemToMatch = it;
95 // Items before |it| have been copied so we don't need to index them.
96 if (it - m_nextItemToIndex > 0)
97 m_nextItemToIndex = it;
98
99 return true;
100 }
101
34 bool PaintController::lastDisplayItemIsNoopBegin() const 102 bool PaintController::lastDisplayItemIsNoopBegin() const
35 { 103 {
36 if (m_newDisplayItemList.isEmpty()) 104 if (m_newDisplayItemList.isEmpty())
37 return false; 105 return false;
38 106
39 const auto& lastDisplayItem = m_newDisplayItemList.last(); 107 const auto& lastDisplayItem = m_newDisplayItemList.last();
40 return lastDisplayItem.isBegin() && !lastDisplayItem.drawsContent(); 108 return lastDisplayItem.isBegin() && !lastDisplayItem.drawsContent();
41 } 109 }
42 110
43 void PaintController::removeLastDisplayItem() 111 void PaintController::removeLastDisplayItem()
(...skipping 12 matching lines...) Expand all
56 #endif 124 #endif
57 m_newDisplayItemList.removeLast(); 125 m_newDisplayItemList.removeLast();
58 126
59 if (RuntimeEnabledFeatures::slimmingPaintV2Enabled()) 127 if (RuntimeEnabledFeatures::slimmingPaintV2Enabled())
60 m_newPaintChunks.decrementDisplayItemIndex(); 128 m_newPaintChunks.decrementDisplayItemIndex();
61 } 129 }
62 130
63 void PaintController::processNewItem(DisplayItem& displayItem) 131 void PaintController::processNewItem(DisplayItem& displayItem)
64 { 132 {
65 DCHECK(!m_constructionDisabled); 133 DCHECK(!m_constructionDisabled);
66 DCHECK(!skippingCache() || !displayItem.isCached());
67 134
68 #if CHECK_DISPLAY_ITEM_CLIENT_ALIVENESS 135 #if CHECK_DISPLAY_ITEM_CLIENT_ALIVENESS
69 if (!skippingCache()) { 136 if (!skippingCache()) {
70 if (displayItem.isCacheable() || displayItem.isCached()) { 137 if (displayItem.isCacheable()) {
71 // Mark the client shouldKeepAlive under this PaintController. 138 // Mark the client shouldKeepAlive under this PaintController.
72 // The status will end after the new display items are committed. 139 // The status will end after the new display items are committed.
73 displayItem.client().beginShouldKeepAlive(this); 140 displayItem.client().beginShouldKeepAlive(this);
74 141
75 if (!m_currentSubsequenceClients.isEmpty()) { 142 if (!m_currentSubsequenceClients.isEmpty()) {
76 // Mark the client shouldKeepAlive under the current subsequence . 143 // Mark the client shouldKeepAlive under the current subsequence .
77 // The status will end when the subsequence owner is invalidated or deleted. 144 // The status will end when the subsequence owner is invalidated or deleted.
78 displayItem.client().beginShouldKeepAlive(m_currentSubsequenceCl ients.last()); 145 displayItem.client().beginShouldKeepAlive(m_currentSubsequenceCl ients.last());
79 } 146 }
80 } 147 }
81 148
82 if (displayItem.getType() == DisplayItem::Subsequence) { 149 if (displayItem.getType() == DisplayItem::Subsequence) {
83 m_currentSubsequenceClients.append(&displayItem.client()); 150 m_currentSubsequenceClients.append(&displayItem.client());
84 } else if (displayItem.getType() == DisplayItem::EndSubsequence) { 151 } else if (displayItem.getType() == DisplayItem::EndSubsequence) {
85 CHECK(m_currentSubsequenceClients.last() == &displayItem.client()); 152 CHECK(m_currentSubsequenceClients.last() == &displayItem.client());
86 m_currentSubsequenceClients.removeLast(); 153 m_currentSubsequenceClients.removeLast();
87 } 154 }
88 } 155 }
89 #endif 156 #endif
90 157
91 if (displayItem.isCached())
92 ++m_numCachedNewItems;
93
94 #if DCHECK_IS_ON() 158 #if DCHECK_IS_ON()
95 // Verify noop begin/end pairs have been removed. 159 // Verify noop begin/end pairs have been removed.
96 if (m_newDisplayItemList.size() >= 2 && displayItem.isEnd()) { 160 if (m_newDisplayItemList.size() >= 2 && displayItem.isEnd()) {
97 const auto& beginDisplayItem = m_newDisplayItemList[m_newDisplayItemList .size() - 2]; 161 const auto& beginDisplayItem = m_newDisplayItemList[m_newDisplayItemList .size() - 2];
98 if (beginDisplayItem.isBegin() && beginDisplayItem.getType() != DisplayI tem::Subsequence && !beginDisplayItem.drawsContent()) 162 if (beginDisplayItem.isBegin() && beginDisplayItem.getType() != DisplayI tem::Subsequence && !beginDisplayItem.drawsContent())
99 DCHECK(!displayItem.isEndAndPairedWith(beginDisplayItem.getType())); 163 DCHECK(!displayItem.isEndAndPairedWith(beginDisplayItem.getType()));
100 } 164 }
101 #endif 165 #endif
102 166
103 if (skippingCache()) 167 if (skippingCache())
104 displayItem.setSkippedCache(); 168 displayItem.setSkippedCache();
105 169
106 #if DCHECK_IS_ON() 170 #if DCHECK_IS_ON()
107 size_t index = findMatchingItemFromIndex(displayItem.nonCachedId(), m_newDis playItemIndicesByClient, m_newDisplayItemList); 171 size_t index = findMatchingItemFromIndex(displayItem.getId(), m_newDisplayIt emIndicesByClient, m_newDisplayItemList);
108 if (index != kNotFound) { 172 if (index != kNotFound) {
109 #ifndef NDEBUG 173 #ifndef NDEBUG
110 showDebugData(); 174 showDebugData();
111 WTFLogAlways("DisplayItem %s has duplicated id with previous %s (index=% d)\n", 175 WTFLogAlways("DisplayItem %s has duplicated id with previous %s (index=% d)\n",
112 displayItem.asDebugString().utf8().data(), m_newDisplayItemList[inde x].asDebugString().utf8().data(), static_cast<int>(index)); 176 displayItem.asDebugString().utf8().data(), m_newDisplayItemList[inde x].asDebugString().utf8().data(), static_cast<int>(index));
113 #endif 177 #endif
114 NOTREACHED(); 178 NOTREACHED();
115 } 179 }
116 addItemToIndexIfNeeded(displayItem, m_newDisplayItemList.size() - 1, m_newDi splayItemIndicesByClient); 180 addItemToIndexIfNeeded(displayItem, m_newDisplayItemList.size() - 1, m_newDi splayItemIndicesByClient);
117 #endif // DCHECK_IS_ON() 181 #endif // DCHECK_IS_ON()
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
151 size_t PaintController::findMatchingItemFromIndex(const DisplayItem::Id& id, con st DisplayItemIndicesByClientMap& displayItemIndicesByClient, const DisplayItemL ist& list) 215 size_t PaintController::findMatchingItemFromIndex(const DisplayItem::Id& id, con st DisplayItemIndicesByClientMap& displayItemIndicesByClient, const DisplayItemL ist& list)
152 { 216 {
153 DisplayItemIndicesByClientMap::const_iterator it = displayItemIndicesByClien t.find(&id.client); 217 DisplayItemIndicesByClientMap::const_iterator it = displayItemIndicesByClien t.find(&id.client);
154 if (it == displayItemIndicesByClient.end()) 218 if (it == displayItemIndicesByClient.end())
155 return kNotFound; 219 return kNotFound;
156 220
157 const Vector<size_t>& indices = it->value; 221 const Vector<size_t>& indices = it->value;
158 for (size_t index : indices) { 222 for (size_t index : indices) {
159 const DisplayItem& existingItem = list[index]; 223 const DisplayItem& existingItem = list[index];
160 DCHECK(!existingItem.hasValidClient() || existingItem.client() == id.cli ent); 224 DCHECK(!existingItem.hasValidClient() || existingItem.client() == id.cli ent);
161 if (id.matches(existingItem)) 225 if (id == existingItem.getId())
162 return index; 226 return index;
163 } 227 }
164 228
165 return kNotFound; 229 return kNotFound;
166 } 230 }
167 231
168 void PaintController::addItemToIndexIfNeeded(const DisplayItem& displayItem, siz e_t index, DisplayItemIndicesByClientMap& displayItemIndicesByClient) 232 void PaintController::addItemToIndexIfNeeded(const DisplayItem& displayItem, siz e_t index, DisplayItemIndicesByClientMap& displayItemIndicesByClient)
169 { 233 {
170 if (!displayItem.isCacheable()) 234 if (!displayItem.isCacheable())
171 return; 235 return;
172 236
173 DisplayItemIndicesByClientMap::iterator it = displayItemIndicesByClient.find (&displayItem.client()); 237 DisplayItemIndicesByClientMap::iterator it = displayItemIndicesByClient.find (&displayItem.client());
174 Vector<size_t>& indices = it == displayItemIndicesByClient.end() ? 238 Vector<size_t>& indices = it == displayItemIndicesByClient.end() ?
175 displayItemIndicesByClient.add(&displayItem.client(), Vector<size_t>()). storedValue->value : it->value; 239 displayItemIndicesByClient.add(&displayItem.client(), Vector<size_t>()). storedValue->value : it->value;
176 indices.append(index); 240 indices.append(index);
177 } 241 }
178 242
179 struct PaintController::OutOfOrderIndexContext { 243 DisplayItemList::iterator PaintController::findCachedItem(const DisplayItem::Id& id)
180 STACK_ALLOCATED();
181 OutOfOrderIndexContext(DisplayItemList::iterator begin) : nextItemToIndex(be gin) { }
182
183 DisplayItemList::iterator nextItemToIndex;
184 DisplayItemIndicesByClientMap displayItemIndicesByClient;
185 };
186
187 DisplayItemList::iterator PaintController::findOutOfOrderCachedItem(const Displa yItem::Id& id, OutOfOrderIndexContext& context)
188 { 244 {
189 DCHECK(clientCacheIsValid(id.client)); 245 DCHECK(clientCacheIsValid(id.client));
190 246
191 size_t foundIndex = findMatchingItemFromIndex(id, context.displayItemIndices ByClient, m_currentPaintArtifact.getDisplayItemList()); 247 // Try to find the item sequentially first. This is fast if the current list and the new list are in
192 if (foundIndex != kNotFound) 248 // the same order around the new item. If found, we don't need to update and lookup the index.
249 DisplayItemList::iterator end = m_currentPaintArtifact.getDisplayItemList(). end();
250 DisplayItemList::iterator it = m_nextItemToMatch;
251 for (; it != end; ++it) {
252 // We encounter an item that has already been copied which indicates we can't do sequential matching.
253 if (!it->hasValidClient())
254 break;
255 if (id == it->getId()) {
256 #if DCHECK_IS_ON()
257 ++m_numSequentialMatches;
258 #endif
259 return it;
260 }
261 // We encounter a different cacheable item which also indicates we can't do sequential matching.
262 if (it->isCacheable())
263 break;
264 }
265
266 size_t foundIndex = findMatchingItemFromIndex(id, m_outOfOrderItemIndices, m _currentPaintArtifact.getDisplayItemList());
267 if (foundIndex != kNotFound) {
268 #if DCHECK_IS_ON()
269 ++m_numOutOfOrderMatches;
270 #endif
193 return m_currentPaintArtifact.getDisplayItemList().begin() + foundIndex; 271 return m_currentPaintArtifact.getDisplayItemList().begin() + foundIndex;
272 }
194 273
195 return findOutOfOrderCachedItemForward(id, context); 274 return findOutOfOrderCachedItemForward(id);
196 } 275 }
197 276
198 // Find forward for the item and index all skipped indexable items. 277 // Find forward for the item and index all skipped indexable items.
199 DisplayItemList::iterator PaintController::findOutOfOrderCachedItemForward(const DisplayItem::Id& id, OutOfOrderIndexContext& context) 278 DisplayItemList::iterator PaintController::findOutOfOrderCachedItemForward(const DisplayItem::Id& id)
200 { 279 {
201 DisplayItemList::iterator currentEnd = m_currentPaintArtifact.getDisplayItem List().end(); 280 DisplayItemList::iterator end = m_currentPaintArtifact.getDisplayItemList(). end();
202 for (; context.nextItemToIndex != currentEnd; ++context.nextItemToIndex) { 281 for (DisplayItemList::iterator it = m_nextItemToIndex; it != end; ++it) {
203 const DisplayItem& item = *context.nextItemToIndex; 282 const DisplayItem& item = *it;
204 DCHECK(item.hasValidClient()); 283 DCHECK(item.hasValidClient());
205 if (id.matches(item)) 284 if (id == item.getId()) {
206 return context.nextItemToIndex++; 285 #if DCHECK_IS_ON()
207 if (item.isCacheable()) 286 ++m_numSequentialMatches;
208 addItemToIndexIfNeeded(item, context.nextItemToIndex - m_currentPain tArtifact.getDisplayItemList().begin(), context.displayItemIndicesByClient); 287 #endif
288 return it;
289 }
290 if (item.isCacheable()) {
291 #if DCHECK_IS_ON()
292 ++m_numIndexedItems;
293 #endif
294 addItemToIndexIfNeeded(item, it - m_currentPaintArtifact.getDisplayI temList().begin(), m_outOfOrderItemIndices);
295 }
209 } 296 }
210 return currentEnd; 297
298 #ifndef NDEBUG
299 showDebugData();
300 LOG(ERROR) << id.client.debugName() << ":" << DisplayItem::typeAsDebugString (id.type) << " not found in current display item list";
301 #endif
302 NOTREACHED();
303 // We did not find the cached display item. This should be impossible, but m ay occur if there is a bug
304 // in the system, such as under-invalidation, incorrect cache checking or du plicate display ids.
305 // In this case, the caller should fall back to repaint the display item.
306 return end;
211 } 307 }
212 308
213 void PaintController::copyCachedSubsequence(const DisplayItemList& currentList, DisplayItemList::iterator& currentIt, DisplayItemList& updatedList, SkPictureGpu Analyzer& gpuAnalyzer) 309 // On return, |it| points to the item after the EndSubsequence item of the subse quence.
310 void PaintController::copyCachedSubsequence(DisplayItemList::iterator& it)
214 { 311 {
215 DCHECK(currentIt->getType() == DisplayItem::Subsequence); 312 DCHECK(it->getType() == DisplayItem::Subsequence);
216 DisplayItem::Id endSubsequenceId(currentIt->client(), DisplayItem::EndSubseq uence); 313 DisplayItem::Id endSubsequenceId(it->client(), DisplayItem::EndSubsequence);
217 do { 314 do {
218 // We should always find the EndSubsequence display item. 315 // We should always find the EndSubsequence display item.
219 DCHECK(currentIt != m_currentPaintArtifact.getDisplayItemList().end()); 316 DCHECK(it != m_currentPaintArtifact.getDisplayItemList().end());
220 DCHECK(currentIt->hasValidClient()); 317 DCHECK(it->hasValidClient());
221 #if CHECK_DISPLAY_ITEM_CLIENT_ALIVENESS 318 #if CHECK_DISPLAY_ITEM_CLIENT_ALIVENESS
222 CHECK(currentIt->client().isAlive()); 319 CHECK(it->client().isAlive());
223 #endif 320 #endif
224 updatedList.appendByMoving(*currentIt, currentList.visualRect(currentIt - m_currentPaintArtifact.getDisplayItemList().begin()), gpuAnalyzer); 321 ++m_numCachedNewItems;
225 ++currentIt; 322 processNewItem(m_newDisplayItemList.appendByMoving(*it));
226 } while (!endSubsequenceId.matches(updatedList.last())); 323 ++it;
324 } while (endSubsequenceId != m_newDisplayItemList.last().getId());
227 } 325 }
228 326
229 static IntRect visualRectForDisplayItem(const DisplayItem& displayItem, const La youtSize& offsetFromLayoutObject) 327 static IntRect visualRectForDisplayItem(const DisplayItem& displayItem, const La youtSize& offsetFromLayoutObject)
230 { 328 {
231 LayoutRect visualRect = displayItem.client().visualRect(); 329 LayoutRect visualRect = displayItem.client().visualRect();
232 visualRect.move(-offsetFromLayoutObject); 330 visualRect.move(-offsetFromLayoutObject);
233 return enclosingIntRect(visualRect); 331 return enclosingIntRect(visualRect);
234 } 332 }
235 333
236 // Update the existing display items by removing invalidated entries, updating 334 void PaintController::resetCurrentListIterators()
237 // repainted ones, and appending new items. 335 {
238 // - For cached drawing display item, copy the corresponding cached DrawingDispl ayItem; 336 m_nextItemToMatch = m_currentPaintArtifact.getDisplayItemList().begin();
239 // - For cached subsequence display item, copy the cached display items between the 337 m_nextItemToIndex = m_nextItemToMatch;
240 // corresponding SubsequenceDisplayItem and EndSubsequenceDisplayItem (incl.); 338 }
241 // - Otherwise, copy the new display item. 339
242 //
243 // The algorithm is O(|m_currentDisplayItemList| + |m_newDisplayItemList|).
244 // Coefficients are related to the ratio of out-of-order CachedDisplayItems
245 // and the average number of (Drawing|Subsequence)DisplayItems per client.
246 //
247 void PaintController::commitNewDisplayItems(const LayoutSize& offsetFromLayoutOb ject) 340 void PaintController::commitNewDisplayItems(const LayoutSize& offsetFromLayoutOb ject)
248 { 341 {
249 TRACE_EVENT2("blink,benchmark", "PaintController::commitNewDisplayItems", 342 TRACE_EVENT2("blink,benchmark", "PaintController::commitNewDisplayItems",
250 "current_display_list_size", (int)m_currentPaintArtifact.getDisplayItemL ist().size(), 343 "current_display_list_size", (int)m_currentPaintArtifact.getDisplayItemL ist().size(),
251 "num_non_cached_new_items", (int)m_newDisplayItemList.size() - m_numCach edNewItems); 344 "num_non_cached_new_items", (int)m_newDisplayItemList.size() - m_numCach edNewItems);
252 m_numCachedNewItems = 0; 345 m_numCachedNewItems = 0;
253 346
254 // These data structures are used during painting only. 347 // These data structures are used during painting only.
255 DCHECK(!skippingCache()); 348 DCHECK(!skippingCache());
256 #if DCHECK_IS_ON() 349 #if DCHECK_IS_ON()
257 m_newDisplayItemIndicesByClient.clear(); 350 m_newDisplayItemIndicesByClient.clear();
258 #endif 351 #endif
259 352
260 SkPictureGpuAnalyzer gpuAnalyzer; 353 SkPictureGpuAnalyzer gpuAnalyzer;
261 354
262 if (m_currentPaintArtifact.isEmpty()) { 355 m_currentCacheGeneration = DisplayItemClient::CacheGenerationOrInvalidationR eason::next();
263 #if DCHECK_IS_ON() 356 for (const auto& item : m_newDisplayItemList) {
264 for (const auto& item : m_newDisplayItemList) 357 // No reason to continue the analysis once we have a veto.
265 DCHECK(!item.isCached()); 358 if (gpuAnalyzer.suitableForGpuRasterization())
359 item.analyzeForGpuRasterization(gpuAnalyzer);
360
361 m_newDisplayItemList.appendVisualRect(visualRectForDisplayItem(item, off setFromLayoutObject));
362
363 if (item.isCacheable())
364 item.client().setDisplayItemsCached(m_currentCacheGeneration);
365 }
366
367 m_newDisplayItemList.removeEmptyBuffers();
368 m_currentPaintArtifact = PaintArtifact(std::move(m_newDisplayItemList), m_ne wPaintChunks.releasePaintChunks(), gpuAnalyzer.suitableForGpuRasterization());
369 resetCurrentListIterators();
370 m_outOfOrderItemIndices.clear();
371
372 // We'll allocate the initial buffer when we start the next paint.
373 m_newDisplayItemList = DisplayItemList(0);
374
375 #if CHECK_DISPLAY_ITEM_CLIENT_ALIVENESS
376 CHECK(m_currentSubsequenceClients.isEmpty());
377 DisplayItemClient::endShouldKeepAliveAllClients(this);
266 #endif 378 #endif
267 379
268 for (const auto& item : m_newDisplayItemList) { 380 #if DCHECK_IS_ON()
269 m_newDisplayItemList.appendVisualRect(visualRectForDisplayItem(item, offsetFromLayoutObject)); 381 m_numSequentialMatches = 0;
270 // No reason to continue the analysis once we have a veto. 382 m_numOutOfOrderMatches = 0;
271 if (gpuAnalyzer.suitableForGpuRasterization()) 383 m_numIndexedItems = 0;
272 item.analyzeForGpuRasterization(gpuAnalyzer);
273 }
274 m_currentPaintArtifact = PaintArtifact(std::move(m_newDisplayItemList), m_newPaintChunks.releasePaintChunks(), gpuAnalyzer.suitableForGpuRasterization() );
275 m_newDisplayItemList = DisplayItemList(kInitialDisplayItemListCapacityBy tes);
276 updateCacheGeneration();
277 return;
278 }
279
280 // Stores indices to valid DrawingDisplayItems in m_currentDisplayItems that have not been matched
281 // by CachedDisplayItems during synchronized matching. The indexed items wil l be matched
282 // by later out-of-order CachedDisplayItems in m_newDisplayItemList. This en sures that when
283 // out-of-order CachedDisplayItems occur, we only traverse at most once over m_currentDisplayItems
284 // looking for potential matches. Thus we can ensure that the algorithm runs in linear time.
285 OutOfOrderIndexContext outOfOrderIndexContext(m_currentPaintArtifact.getDisp layItemList().begin());
286
287 // TODO(jbroman): Consider revisiting this heuristic.
288 DisplayItemList updatedList(std::max(m_currentPaintArtifact.getDisplayItemLi st().usedCapacityInBytes(), m_newDisplayItemList.usedCapacityInBytes()));
289 Vector<PaintChunk> updatedPaintChunks;
290 DisplayItemList::iterator currentIt = m_currentPaintArtifact.getDisplayItemL ist().begin();
291 DisplayItemList::iterator currentEnd = m_currentPaintArtifact.getDisplayItem List().end();
292 for (DisplayItemList::iterator newIt = m_newDisplayItemList.begin(); newIt ! = m_newDisplayItemList.end(); ++newIt) {
293 const DisplayItem& newDisplayItem = *newIt;
294 const DisplayItem::Id newDisplayItemId = newDisplayItem.nonCachedId();
295 bool newDisplayItemHasCachedType = newDisplayItem.getType() != newDispla yItemId.type;
296
297 bool isSynchronized = currentIt != currentEnd && newDisplayItemId.matche s(*currentIt);
298
299 if (newDisplayItemHasCachedType) {
300 DCHECK(newDisplayItem.isCached());
301 #if CHECK_DISPLAY_ITEM_CLIENT_ALIVENESS
302 CHECK(clientCacheIsValid(newDisplayItem.client()));
303 #endif 384 #endif
304 if (!isSynchronized) {
305 currentIt = findOutOfOrderCachedItem(newDisplayItemId, outOfOrde rIndexContext);
306
307 if (currentIt == currentEnd) {
308 #ifndef NDEBUG
309 showDebugData();
310 WTFLogAlways("%s not found in m_currentDisplayItemList\n", n ewDisplayItem.asDebugString().utf8().data());
311 #endif
312 NOTREACHED();
313 // We did not find the cached display item. This should be i mpossible, but may occur if there is a bug
314 // in the system, such as under-invalidation, incorrect cach e checking or duplicate display ids.
315 // In this case, attempt to recover rather than crashing or bailing on display of the rest of the display list.
316 continue;
317 }
318 }
319 #if DCHECK_IS_ON()
320 if (RuntimeEnabledFeatures::slimmingPaintUnderInvalidationCheckingEn abled()) {
321 DisplayItemList::iterator temp = currentIt;
322 checkUnderInvalidation(newIt, temp);
323 }
324 #endif
325 if (newDisplayItem.isCachedDrawing()) {
326 updatedList.appendByMoving(*currentIt, m_currentPaintArtifact.ge tDisplayItemList().visualRect(currentIt - m_currentPaintArtifact.getDisplayItemL ist().begin()),
327 gpuAnalyzer);
328 ++currentIt;
329 } else {
330 DCHECK(newDisplayItem.getType() == DisplayItem::CachedSubsequenc e);
331 copyCachedSubsequence(m_currentPaintArtifact.getDisplayItemList( ), currentIt, updatedList, gpuAnalyzer);
332 DCHECK(updatedList.last().getType() == DisplayItem::EndSubsequen ce);
333 }
334 } else {
335 DCHECK(!newDisplayItem.isDrawing()
336 || newDisplayItem.skippedCache()
337 || !clientCacheIsValid(newDisplayItem.client()));
338
339 updatedList.appendByMoving(*newIt, visualRectForDisplayItem(*newIt, offsetFromLayoutObject), gpuAnalyzer);
340
341 if (isSynchronized)
342 ++currentIt;
343 }
344 // Items before currentIt should have been copied so we don't need to in dex them.
345 if (currentIt - outOfOrderIndexContext.nextItemToIndex > 0)
346 outOfOrderIndexContext.nextItemToIndex = currentIt;
347 }
348
349 // TODO(jbroman): When subsequence caching applies to SPv2, we'll need to
350 // merge the paint chunks as well.
351 m_currentPaintArtifact = PaintArtifact(std::move(updatedList), m_newPaintChu nks.releasePaintChunks(), gpuAnalyzer.suitableForGpuRasterization());
352
353 m_newDisplayItemList = DisplayItemList(kInitialDisplayItemListCapacityBytes) ;
354 updateCacheGeneration();
355 } 385 }
356 386
357 size_t PaintController::approximateUnsharedMemoryUsage() const 387 size_t PaintController::approximateUnsharedMemoryUsage() const
358 { 388 {
359 size_t memoryUsage = sizeof(*this); 389 size_t memoryUsage = sizeof(*this);
360 390
361 // Memory outside this class due to m_currentPaintArtifact. 391 // Memory outside this class due to m_currentPaintArtifact.
362 memoryUsage += m_currentPaintArtifact.approximateUnsharedMemoryUsage() - siz eof(m_currentPaintArtifact); 392 memoryUsage += m_currentPaintArtifact.approximateUnsharedMemoryUsage() - siz eof(m_currentPaintArtifact);
363 393
364 // TODO(jbroman): If display items begin to have significant external memory 394 // TODO(jbroman): If display items begin to have significant external memory
365 // usage that's not shared with the embedder, we should account for it here. 395 // usage that's not shared with the embedder, we should account for it here.
366 // 396 //
367 // External objects, shared with the embedder, such as SkPicture, should be 397 // External objects, shared with the embedder, such as SkPicture, should be
368 // excluded to avoid double counting. It is the embedder's responsibility to 398 // excluded to avoid double counting. It is the embedder's responsibility to
369 // count such objects. 399 // count such objects.
370 // 400 //
371 // At time of writing, the only known case of unshared external memory was 401 // At time of writing, the only known case of unshared external memory was
372 // the rounded clips vector in ClipDisplayItem, which is not expected to 402 // the rounded clips vector in ClipDisplayItem, which is not expected to
373 // contribute significantly to memory usage. 403 // contribute significantly to memory usage.
374 404
375 // Memory outside this class due to m_newDisplayItemList. 405 // Memory outside this class due to m_newDisplayItemList.
376 DCHECK(m_newDisplayItemList.isEmpty()); 406 DCHECK(m_newDisplayItemList.isEmpty());
377 memoryUsage += m_newDisplayItemList.memoryUsageInBytes(); 407 memoryUsage += m_newDisplayItemList.memoryUsageInBytes();
378 408
379 return memoryUsage; 409 return memoryUsage;
380 } 410 }
381 411
382 void PaintController::updateCacheGeneration()
383 {
384 m_currentCacheGeneration = DisplayItemClient::CacheGenerationOrInvalidationR eason::next();
385 for (const DisplayItem& displayItem : m_currentPaintArtifact.getDisplayItemL ist()) {
386 if (!displayItem.isCacheable())
387 continue;
388 displayItem.client().setDisplayItemsCached(m_currentCacheGeneration);
389 }
390 #if CHECK_DISPLAY_ITEM_CLIENT_ALIVENESS
391 CHECK(m_currentSubsequenceClients.isEmpty());
392 DisplayItemClient::endShouldKeepAliveAllClients(this);
393 #endif
394 }
395
396 void PaintController::appendDebugDrawingAfterCommit(const DisplayItemClient& dis playItemClient, PassRefPtr<SkPicture> picture, const LayoutSize& offsetFromLayou tObject) 412 void PaintController::appendDebugDrawingAfterCommit(const DisplayItemClient& dis playItemClient, PassRefPtr<SkPicture> picture, const LayoutSize& offsetFromLayou tObject)
397 { 413 {
398 DCHECK(m_newDisplayItemList.isEmpty()); 414 DCHECK(m_newDisplayItemList.isEmpty());
399 DrawingDisplayItem& displayItem = m_currentPaintArtifact.getDisplayItemList( ).allocateAndConstruct<DrawingDisplayItem>(displayItemClient, DisplayItem::Debug Drawing, picture); 415 DrawingDisplayItem& displayItem = m_currentPaintArtifact.getDisplayItemList( ).allocateAndConstruct<DrawingDisplayItem>(displayItemClient, DisplayItem::Debug Drawing, picture);
400 displayItem.setSkippedCache(); 416 displayItem.setSkippedCache();
401 m_currentPaintArtifact.getDisplayItemList().appendVisualRect(visualRectForDi splayItem(displayItem, offsetFromLayoutObject)); 417 m_currentPaintArtifact.getDisplayItemList().appendVisualRect(visualRectForDi splayItem(displayItem, offsetFromLayoutObject));
418
419 resetCurrentListIterators();
402 } 420 }
403 421
404 #if DCHECK_IS_ON() 422 #if 0 // DCHECK_IS_ON()
423 // TODO(wangxianzhu): Fix under-invalidation checking for the new caching method .
405 424
406 void PaintController::checkUnderInvalidation(DisplayItemList::iterator& newIt, D isplayItemList::iterator& currentIt) 425 void PaintController::checkUnderInvalidation(DisplayItemList::iterator& newIt, D isplayItemList::iterator& currentIt)
407 { 426 {
408 DCHECK(RuntimeEnabledFeatures::slimmingPaintUnderInvalidationCheckingEnabled ()); 427 DCHECK(RuntimeEnabledFeatures::slimmingPaintUnderInvalidationCheckingEnabled ());
409 DCHECK(newIt->isCached());
410 428
411 // When under-invalidation-checking is enabled, the forced painting is follo wing the cached display item. 429 // When under-invalidation-checking is enabled, the forced painting is follo wing the cached display item.
412 DisplayItem::Type nextItemType = DisplayItem::nonCachedType(newIt->getType() ); 430 DisplayItem::Type nextItemType = DisplayItem::nonCachedType(newIt->getType() );
413 ++newIt; 431 ++newIt;
414 DCHECK(newIt->getType() == nextItemType); 432 DCHECK(newIt->getType() == nextItemType);
415 433
416 if (newIt->isDrawing()) { 434 if (newIt->isDrawing()) {
417 checkCachedDisplayItemIsUnchanged("", *newIt, *currentIt); 435 checkCachedDisplayItemIsUnchanged("", *newIt, *currentIt);
418 return; 436 return;
419 } 437 }
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
517 535
518 void PaintController::showDebugData() const 536 void PaintController::showDebugData() const
519 { 537 {
520 WTFLogAlways("current display item list: [%s]\n", displayItemListAsDebugStri ng(m_currentPaintArtifact.getDisplayItemList()).utf8().data()); 538 WTFLogAlways("current display item list: [%s]\n", displayItemListAsDebugStri ng(m_currentPaintArtifact.getDisplayItemList()).utf8().data());
521 WTFLogAlways("new display item list: [%s]\n", displayItemListAsDebugString(m _newDisplayItemList).utf8().data()); 539 WTFLogAlways("new display item list: [%s]\n", displayItemListAsDebugString(m _newDisplayItemList).utf8().data());
522 } 540 }
523 541
524 #endif // ifndef NDEBUG 542 #endif // ifndef NDEBUG
525 543
526 } // namespace blink 544 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698