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

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: Address pdr's comments 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)) ;
pdr. 2016/07/12 20:09:35 Super nit: "it" -> "cachedItemIterator" or "cached
Xianzhu 2016/07/13 00:28:21 Done.
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 // TODO(crbug.com/596983): Implement subsequence caching for spv2.
72 // The problem is in copyCachedSubsequence() which fails to handle PaintChun kProperties
73 // of chunks containing cached display items. We need to find the previous
74 // PaintChunkProperties and ensure they are valid in the current paint prope rty tree.
75 if (RuntimeEnabledFeatures::slimmingPaintV2Enabled())
76 return false;
77
78 if (displayItemConstructionIsDisabled() || subsequenceCachingIsDisabled())
79 return false;
80
81 if (!clientCacheIsValid(client))
82 return false;
83
84 #if ENABLE(ASSERT)
85 // When under-invalidation checking is enabled, we output CachedDrawing disp lay item
86 // followed by the display item containing forced painting.
87 if (RuntimeEnabledFeatures::slimmingPaintUnderInvalidationCheckingEnabled())
88 return false;
89 #endif
90
91 DisplayItemList::iterator it = findCachedItem(DisplayItem::Id(client, Displa yItem::Subsequence));
pdr. 2016/07/12 20:09:35 Super nit: "it" -> "firstCachedItemIterator" or "f
Xianzhu 2016/07/13 00:28:21 Renamed to cachedItem instead of firstCachedItem b
92 if (it == m_currentPaintArtifact.getDisplayItemList().end()) {
93 NOTREACHED();
94 return false;
95 }
96
97 // |it| will point to the first item after the subsequence or end of the cur rent list.
pdr. 2016/07/12 20:09:35 Before copyCachedSubsequence, won't |it| point to
Xianzhu 2016/07/13 00:28:21 Before copyCachedSubsequence |it| points to the fi
98 ensureNewDisplayItemListInitialCapacity();
99 copyCachedSubsequence(it);
100
101 m_nextItemToMatch = it;
102 // Items before |it| have been copied so we don't need to index them.
103 if (it - m_nextItemToIndex > 0)
104 m_nextItemToIndex = it;
105
106 return true;
107 }
108
34 bool PaintController::lastDisplayItemIsNoopBegin() const 109 bool PaintController::lastDisplayItemIsNoopBegin() const
35 { 110 {
36 if (m_newDisplayItemList.isEmpty()) 111 if (m_newDisplayItemList.isEmpty())
37 return false; 112 return false;
38 113
39 const auto& lastDisplayItem = m_newDisplayItemList.last(); 114 const auto& lastDisplayItem = m_newDisplayItemList.last();
40 return lastDisplayItem.isBegin() && !lastDisplayItem.drawsContent(); 115 return lastDisplayItem.isBegin() && !lastDisplayItem.drawsContent();
41 } 116 }
42 117
43 void PaintController::removeLastDisplayItem() 118 void PaintController::removeLastDisplayItem()
(...skipping 12 matching lines...) Expand all
56 #endif 131 #endif
57 m_newDisplayItemList.removeLast(); 132 m_newDisplayItemList.removeLast();
58 133
59 if (RuntimeEnabledFeatures::slimmingPaintV2Enabled()) 134 if (RuntimeEnabledFeatures::slimmingPaintV2Enabled())
60 m_newPaintChunks.decrementDisplayItemIndex(); 135 m_newPaintChunks.decrementDisplayItemIndex();
61 } 136 }
62 137
63 void PaintController::processNewItem(DisplayItem& displayItem) 138 void PaintController::processNewItem(DisplayItem& displayItem)
64 { 139 {
65 DCHECK(!m_constructionDisabled); 140 DCHECK(!m_constructionDisabled);
66 DCHECK(!skippingCache() || !displayItem.isCached());
67 141
68 #if CHECK_DISPLAY_ITEM_CLIENT_ALIVENESS 142 #if CHECK_DISPLAY_ITEM_CLIENT_ALIVENESS
69 if (!skippingCache()) { 143 if (!skippingCache()) {
70 if (displayItem.isCacheable() || displayItem.isCached()) { 144 if (displayItem.isCacheable()) {
71 // Mark the client shouldKeepAlive under this PaintController. 145 // Mark the client shouldKeepAlive under this PaintController.
72 // The status will end after the new display items are committed. 146 // The status will end after the new display items are committed.
73 displayItem.client().beginShouldKeepAlive(this); 147 displayItem.client().beginShouldKeepAlive(this);
74 148
75 if (!m_currentSubsequenceClients.isEmpty()) { 149 if (!m_currentSubsequenceClients.isEmpty()) {
76 // Mark the client shouldKeepAlive under the current subsequence . 150 // Mark the client shouldKeepAlive under the current subsequence .
77 // The status will end when the subsequence owner is invalidated or deleted. 151 // The status will end when the subsequence owner is invalidated or deleted.
78 displayItem.client().beginShouldKeepAlive(m_currentSubsequenceCl ients.last()); 152 displayItem.client().beginShouldKeepAlive(m_currentSubsequenceCl ients.last());
79 } 153 }
80 } 154 }
81 155
82 if (displayItem.getType() == DisplayItem::Subsequence) { 156 if (displayItem.getType() == DisplayItem::Subsequence) {
83 m_currentSubsequenceClients.append(&displayItem.client()); 157 m_currentSubsequenceClients.append(&displayItem.client());
84 } else if (displayItem.getType() == DisplayItem::EndSubsequence) { 158 } else if (displayItem.getType() == DisplayItem::EndSubsequence) {
85 CHECK(m_currentSubsequenceClients.last() == &displayItem.client()); 159 CHECK(m_currentSubsequenceClients.last() == &displayItem.client());
86 m_currentSubsequenceClients.removeLast(); 160 m_currentSubsequenceClients.removeLast();
87 } 161 }
88 } 162 }
89 #endif 163 #endif
90 164
91 if (displayItem.isCached())
92 ++m_numCachedNewItems;
93
94 #if DCHECK_IS_ON() 165 #if DCHECK_IS_ON()
95 // Verify noop begin/end pairs have been removed. 166 // Verify noop begin/end pairs have been removed.
96 if (m_newDisplayItemList.size() >= 2 && displayItem.isEnd()) { 167 if (m_newDisplayItemList.size() >= 2 && displayItem.isEnd()) {
97 const auto& beginDisplayItem = m_newDisplayItemList[m_newDisplayItemList .size() - 2]; 168 const auto& beginDisplayItem = m_newDisplayItemList[m_newDisplayItemList .size() - 2];
98 if (beginDisplayItem.isBegin() && beginDisplayItem.getType() != DisplayI tem::Subsequence && !beginDisplayItem.drawsContent()) 169 if (beginDisplayItem.isBegin() && beginDisplayItem.getType() != DisplayI tem::Subsequence && !beginDisplayItem.drawsContent())
99 DCHECK(!displayItem.isEndAndPairedWith(beginDisplayItem.getType())); 170 DCHECK(!displayItem.isEndAndPairedWith(beginDisplayItem.getType()));
100 } 171 }
101 #endif 172 #endif
102 173
103 if (skippingCache()) 174 if (skippingCache())
104 displayItem.setSkippedCache(); 175 displayItem.setSkippedCache();
105 176
106 #if DCHECK_IS_ON() 177 #if DCHECK_IS_ON()
107 size_t index = findMatchingItemFromIndex(displayItem.nonCachedId(), m_newDis playItemIndicesByClient, m_newDisplayItemList); 178 size_t index = findMatchingItemFromIndex(displayItem.getId(), m_newDisplayIt emIndicesByClient, m_newDisplayItemList);
108 if (index != kNotFound) { 179 if (index != kNotFound) {
109 #ifndef NDEBUG 180 #ifndef NDEBUG
110 showDebugData(); 181 showDebugData();
111 WTFLogAlways("DisplayItem %s has duplicated id with previous %s (index=% d)\n", 182 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)); 183 displayItem.asDebugString().utf8().data(), m_newDisplayItemList[inde x].asDebugString().utf8().data(), static_cast<int>(index));
113 #endif 184 #endif
114 NOTREACHED(); 185 NOTREACHED();
115 } 186 }
116 addItemToIndexIfNeeded(displayItem, m_newDisplayItemList.size() - 1, m_newDi splayItemIndicesByClient); 187 addItemToIndexIfNeeded(displayItem, m_newDisplayItemList.size() - 1, m_newDi splayItemIndicesByClient);
117 #endif // DCHECK_IS_ON() 188 #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) 222 size_t PaintController::findMatchingItemFromIndex(const DisplayItem::Id& id, con st DisplayItemIndicesByClientMap& displayItemIndicesByClient, const DisplayItemL ist& list)
152 { 223 {
153 DisplayItemIndicesByClientMap::const_iterator it = displayItemIndicesByClien t.find(&id.client); 224 DisplayItemIndicesByClientMap::const_iterator it = displayItemIndicesByClien t.find(&id.client);
154 if (it == displayItemIndicesByClient.end()) 225 if (it == displayItemIndicesByClient.end())
155 return kNotFound; 226 return kNotFound;
156 227
157 const Vector<size_t>& indices = it->value; 228 const Vector<size_t>& indices = it->value;
158 for (size_t index : indices) { 229 for (size_t index : indices) {
159 const DisplayItem& existingItem = list[index]; 230 const DisplayItem& existingItem = list[index];
160 DCHECK(!existingItem.hasValidClient() || existingItem.client() == id.cli ent); 231 DCHECK(!existingItem.hasValidClient() || existingItem.client() == id.cli ent);
161 if (id.matches(existingItem)) 232 if (id == existingItem.getId())
162 return index; 233 return index;
163 } 234 }
164 235
165 return kNotFound; 236 return kNotFound;
166 } 237 }
167 238
168 void PaintController::addItemToIndexIfNeeded(const DisplayItem& displayItem, siz e_t index, DisplayItemIndicesByClientMap& displayItemIndicesByClient) 239 void PaintController::addItemToIndexIfNeeded(const DisplayItem& displayItem, siz e_t index, DisplayItemIndicesByClientMap& displayItemIndicesByClient)
169 { 240 {
170 if (!displayItem.isCacheable()) 241 if (!displayItem.isCacheable())
171 return; 242 return;
172 243
173 DisplayItemIndicesByClientMap::iterator it = displayItemIndicesByClient.find (&displayItem.client()); 244 DisplayItemIndicesByClientMap::iterator it = displayItemIndicesByClient.find (&displayItem.client());
174 Vector<size_t>& indices = it == displayItemIndicesByClient.end() ? 245 Vector<size_t>& indices = it == displayItemIndicesByClient.end() ?
175 displayItemIndicesByClient.add(&displayItem.client(), Vector<size_t>()). storedValue->value : it->value; 246 displayItemIndicesByClient.add(&displayItem.client(), Vector<size_t>()). storedValue->value : it->value;
176 indices.append(index); 247 indices.append(index);
177 } 248 }
178 249
179 struct PaintController::OutOfOrderIndexContext { 250 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 { 251 {
189 DCHECK(clientCacheIsValid(id.client)); 252 DCHECK(clientCacheIsValid(id.client));
190 253
191 size_t foundIndex = findMatchingItemFromIndex(id, context.displayItemIndices ByClient, m_currentPaintArtifact.getDisplayItemList()); 254 // Try to find the item sequentially first. This is fast if the current list and the new list are in
192 if (foundIndex != kNotFound) 255 // the same order around the new item. If found, we don't need to update and lookup the index.
256 DisplayItemList::iterator end = m_currentPaintArtifact.getDisplayItemList(). end();
257 DisplayItemList::iterator it = m_nextItemToMatch;
258 for (; it != end; ++it) {
259 // We encounter an item that has already been copied which indicates we can't do sequential matching.
260 if (!it->hasValidClient())
261 break;
262 if (id == it->getId()) {
263 #if DCHECK_IS_ON()
264 ++m_numSequentialMatches;
265 #endif
266 return it;
267 }
268 // We encounter a different cacheable item which also indicates we can't do sequential matching.
269 if (it->isCacheable())
270 break;
271 }
272
273 size_t foundIndex = findMatchingItemFromIndex(id, m_outOfOrderItemIndices, m _currentPaintArtifact.getDisplayItemList());
274 if (foundIndex != kNotFound) {
275 #if DCHECK_IS_ON()
276 ++m_numOutOfOrderMatches;
277 #endif
193 return m_currentPaintArtifact.getDisplayItemList().begin() + foundIndex; 278 return m_currentPaintArtifact.getDisplayItemList().begin() + foundIndex;
279 }
194 280
195 return findOutOfOrderCachedItemForward(id, context); 281 return findOutOfOrderCachedItemForward(id);
196 } 282 }
197 283
198 // Find forward for the item and index all skipped indexable items. 284 // Find forward for the item and index all skipped indexable items.
199 DisplayItemList::iterator PaintController::findOutOfOrderCachedItemForward(const DisplayItem::Id& id, OutOfOrderIndexContext& context) 285 DisplayItemList::iterator PaintController::findOutOfOrderCachedItemForward(const DisplayItem::Id& id)
200 { 286 {
201 DisplayItemList::iterator currentEnd = m_currentPaintArtifact.getDisplayItem List().end(); 287 DisplayItemList::iterator end = m_currentPaintArtifact.getDisplayItemList(). end();
202 for (; context.nextItemToIndex != currentEnd; ++context.nextItemToIndex) { 288 for (DisplayItemList::iterator it = m_nextItemToIndex; it != end; ++it) {
203 const DisplayItem& item = *context.nextItemToIndex; 289 const DisplayItem& item = *it;
204 DCHECK(item.hasValidClient()); 290 DCHECK(item.hasValidClient());
205 if (id.matches(item)) 291 if (id == item.getId()) {
206 return context.nextItemToIndex++; 292 #if DCHECK_IS_ON()
207 if (item.isCacheable()) 293 ++m_numSequentialMatches;
208 addItemToIndexIfNeeded(item, context.nextItemToIndex - m_currentPain tArtifact.getDisplayItemList().begin(), context.displayItemIndicesByClient); 294 #endif
295 return it;
296 }
297 if (item.isCacheable()) {
298 #if DCHECK_IS_ON()
299 ++m_numIndexedItems;
300 #endif
301 addItemToIndexIfNeeded(item, it - m_currentPaintArtifact.getDisplayI temList().begin(), m_outOfOrderItemIndices);
302 }
209 } 303 }
210 return currentEnd; 304
305 #ifndef NDEBUG
306 showDebugData();
307 LOG(ERROR) << id.client.debugName() << ":" << DisplayItem::typeAsDebugString (id.type) << " not found in current display item list";
308 #endif
309 NOTREACHED();
310 // We did not find the cached display item. This should be impossible, but m ay occur if there is a bug
311 // in the system, such as under-invalidation, incorrect cache checking or du plicate display ids.
312 // In this case, the caller should fall back to repaint the display item.
313 return end;
211 } 314 }
212 315
213 void PaintController::copyCachedSubsequence(const DisplayItemList& currentList, DisplayItemList::iterator& currentIt, DisplayItemList& updatedList, SkPictureGpu Analyzer& gpuAnalyzer) 316 // On return, |it| points to the item after the EndSubsequence item of the subse quence.
317 void PaintController::copyCachedSubsequence(DisplayItemList::iterator& it)
214 { 318 {
215 DCHECK(currentIt->getType() == DisplayItem::Subsequence); 319 DCHECK(it->getType() == DisplayItem::Subsequence);
216 DisplayItem::Id endSubsequenceId(currentIt->client(), DisplayItem::EndSubseq uence); 320 DisplayItem::Id endSubsequenceId(it->client(), DisplayItem::EndSubsequence);
217 do { 321 do {
218 // We should always find the EndSubsequence display item. 322 // We should always find the EndSubsequence display item.
219 DCHECK(currentIt != m_currentPaintArtifact.getDisplayItemList().end()); 323 DCHECK(it != m_currentPaintArtifact.getDisplayItemList().end());
220 DCHECK(currentIt->hasValidClient()); 324 DCHECK(it->hasValidClient());
221 #if CHECK_DISPLAY_ITEM_CLIENT_ALIVENESS 325 #if CHECK_DISPLAY_ITEM_CLIENT_ALIVENESS
222 CHECK(currentIt->client().isAlive()); 326 CHECK(it->client().isAlive());
223 #endif 327 #endif
224 updatedList.appendByMoving(*currentIt, currentList.visualRect(currentIt - m_currentPaintArtifact.getDisplayItemList().begin()), gpuAnalyzer); 328 ++m_numCachedNewItems;
225 ++currentIt; 329 processNewItem(m_newDisplayItemList.appendByMoving(*it));
226 } while (!endSubsequenceId.matches(updatedList.last())); 330 ++it;
331 } while (endSubsequenceId != m_newDisplayItemList.last().getId());
227 } 332 }
228 333
229 static IntRect visualRectForDisplayItem(const DisplayItem& displayItem, const La youtSize& offsetFromLayoutObject) 334 static IntRect visualRectForDisplayItem(const DisplayItem& displayItem, const La youtSize& offsetFromLayoutObject)
230 { 335 {
231 LayoutRect visualRect = displayItem.client().visualRect(); 336 LayoutRect visualRect = displayItem.client().visualRect();
232 visualRect.move(-offsetFromLayoutObject); 337 visualRect.move(-offsetFromLayoutObject);
233 return enclosingIntRect(visualRect); 338 return enclosingIntRect(visualRect);
234 } 339 }
235 340
236 // Update the existing display items by removing invalidated entries, updating 341 void PaintController::resetCurrentListIterators()
237 // repainted ones, and appending new items. 342 {
238 // - For cached drawing display item, copy the corresponding cached DrawingDispl ayItem; 343 m_nextItemToMatch = m_currentPaintArtifact.getDisplayItemList().begin();
239 // - For cached subsequence display item, copy the cached display items between the 344 m_nextItemToIndex = m_nextItemToMatch;
240 // corresponding SubsequenceDisplayItem and EndSubsequenceDisplayItem (incl.); 345 }
241 // - Otherwise, copy the new display item. 346
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) 347 void PaintController::commitNewDisplayItems(const LayoutSize& offsetFromLayoutOb ject)
248 { 348 {
249 TRACE_EVENT2("blink,benchmark", "PaintController::commitNewDisplayItems", 349 TRACE_EVENT2("blink,benchmark", "PaintController::commitNewDisplayItems",
250 "current_display_list_size", (int)m_currentPaintArtifact.getDisplayItemL ist().size(), 350 "current_display_list_size", (int)m_currentPaintArtifact.getDisplayItemL ist().size(),
251 "num_non_cached_new_items", (int)m_newDisplayItemList.size() - m_numCach edNewItems); 351 "num_non_cached_new_items", (int)m_newDisplayItemList.size() - m_numCach edNewItems);
252 m_numCachedNewItems = 0; 352 m_numCachedNewItems = 0;
253 353
254 // These data structures are used during painting only. 354 // These data structures are used during painting only.
255 DCHECK(!skippingCache()); 355 DCHECK(!skippingCache());
256 #if DCHECK_IS_ON() 356 #if DCHECK_IS_ON()
257 m_newDisplayItemIndicesByClient.clear(); 357 m_newDisplayItemIndicesByClient.clear();
258 #endif 358 #endif
259 359
260 SkPictureGpuAnalyzer gpuAnalyzer; 360 SkPictureGpuAnalyzer gpuAnalyzer;
261 361
262 if (m_currentPaintArtifact.isEmpty()) { 362 m_currentCacheGeneration = DisplayItemClient::CacheGenerationOrInvalidationR eason::next();
263 #if DCHECK_IS_ON() 363 for (const auto& item : m_newDisplayItemList) {
264 for (const auto& item : m_newDisplayItemList) 364 // No reason to continue the analysis once we have a veto.
265 DCHECK(!item.isCached()); 365 if (gpuAnalyzer.suitableForGpuRasterization())
366 item.analyzeForGpuRasterization(gpuAnalyzer);
367
368 m_newDisplayItemList.appendVisualRect(visualRectForDisplayItem(item, off setFromLayoutObject));
369
370 if (item.isCacheable())
371 item.client().setDisplayItemsCached(m_currentCacheGeneration);
372 }
373
374 // The new list will not be appended to again so we can release unused memor y.
375 m_newDisplayItemList.shrinkToFit();
376 m_currentPaintArtifact = PaintArtifact(std::move(m_newDisplayItemList), m_ne wPaintChunks.releasePaintChunks(), gpuAnalyzer.suitableForGpuRasterization());
377 resetCurrentListIterators();
378 m_outOfOrderItemIndices.clear();
379
380 // We'll allocate the initial buffer when we start the next paint.
381 m_newDisplayItemList = DisplayItemList(0);
382
383 #if CHECK_DISPLAY_ITEM_CLIENT_ALIVENESS
384 CHECK(m_currentSubsequenceClients.isEmpty());
385 DisplayItemClient::endShouldKeepAliveAllClients(this);
266 #endif 386 #endif
267 387
268 for (const auto& item : m_newDisplayItemList) { 388 #if DCHECK_IS_ON()
269 m_newDisplayItemList.appendVisualRect(visualRectForDisplayItem(item, offsetFromLayoutObject)); 389 m_numSequentialMatches = 0;
270 // No reason to continue the analysis once we have a veto. 390 m_numOutOfOrderMatches = 0;
271 if (gpuAnalyzer.suitableForGpuRasterization()) 391 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 392 #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 } 393 }
356 394
357 size_t PaintController::approximateUnsharedMemoryUsage() const 395 size_t PaintController::approximateUnsharedMemoryUsage() const
358 { 396 {
359 size_t memoryUsage = sizeof(*this); 397 size_t memoryUsage = sizeof(*this);
360 398
361 // Memory outside this class due to m_currentPaintArtifact. 399 // Memory outside this class due to m_currentPaintArtifact.
362 memoryUsage += m_currentPaintArtifact.approximateUnsharedMemoryUsage() - siz eof(m_currentPaintArtifact); 400 memoryUsage += m_currentPaintArtifact.approximateUnsharedMemoryUsage() - siz eof(m_currentPaintArtifact);
363 401
364 // TODO(jbroman): If display items begin to have significant external memory 402 // 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. 403 // usage that's not shared with the embedder, we should account for it here.
366 // 404 //
367 // External objects, shared with the embedder, such as SkPicture, should be 405 // External objects, shared with the embedder, such as SkPicture, should be
368 // excluded to avoid double counting. It is the embedder's responsibility to 406 // excluded to avoid double counting. It is the embedder's responsibility to
369 // count such objects. 407 // count such objects.
370 // 408 //
371 // At time of writing, the only known case of unshared external memory was 409 // 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 410 // the rounded clips vector in ClipDisplayItem, which is not expected to
373 // contribute significantly to memory usage. 411 // contribute significantly to memory usage.
374 412
375 // Memory outside this class due to m_newDisplayItemList. 413 // Memory outside this class due to m_newDisplayItemList.
376 DCHECK(m_newDisplayItemList.isEmpty()); 414 DCHECK(m_newDisplayItemList.isEmpty());
377 memoryUsage += m_newDisplayItemList.memoryUsageInBytes(); 415 memoryUsage += m_newDisplayItemList.memoryUsageInBytes();
378 416
379 return memoryUsage; 417 return memoryUsage;
380 } 418 }
381 419
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) 420 void PaintController::appendDebugDrawingAfterCommit(const DisplayItemClient& dis playItemClient, PassRefPtr<SkPicture> picture, const LayoutSize& offsetFromLayou tObject)
397 { 421 {
398 DCHECK(m_newDisplayItemList.isEmpty()); 422 DCHECK(m_newDisplayItemList.isEmpty());
399 DrawingDisplayItem& displayItem = m_currentPaintArtifact.getDisplayItemList( ).allocateAndConstruct<DrawingDisplayItem>(displayItemClient, DisplayItem::Debug Drawing, picture); 423 DrawingDisplayItem& displayItem = m_currentPaintArtifact.getDisplayItemList( ).allocateAndConstruct<DrawingDisplayItem>(displayItemClient, DisplayItem::Debug Drawing, picture);
400 displayItem.setSkippedCache(); 424 displayItem.setSkippedCache();
401 m_currentPaintArtifact.getDisplayItemList().appendVisualRect(visualRectForDi splayItem(displayItem, offsetFromLayoutObject)); 425 m_currentPaintArtifact.getDisplayItemList().appendVisualRect(visualRectForDi splayItem(displayItem, offsetFromLayoutObject));
426
427 resetCurrentListIterators();
pdr. 2016/07/12 20:09:35 Why is this needed?
Xianzhu 2016/07/13 00:28:21 We need to reset the iterators after mutation of t
402 } 428 }
403 429
404 #if DCHECK_IS_ON() 430 #if 0 // DCHECK_IS_ON()
431 // TODO(wangxianzhu): Fix under-invalidation checking for the new caching method .
405 432
406 void PaintController::checkUnderInvalidation(DisplayItemList::iterator& newIt, D isplayItemList::iterator& currentIt) 433 void PaintController::checkUnderInvalidation(DisplayItemList::iterator& newIt, D isplayItemList::iterator& currentIt)
407 { 434 {
408 DCHECK(RuntimeEnabledFeatures::slimmingPaintUnderInvalidationCheckingEnabled ()); 435 DCHECK(RuntimeEnabledFeatures::slimmingPaintUnderInvalidationCheckingEnabled ());
409 DCHECK(newIt->isCached());
410 436
411 // When under-invalidation-checking is enabled, the forced painting is follo wing the cached display item. 437 // When under-invalidation-checking is enabled, the forced painting is follo wing the cached display item.
412 DisplayItem::Type nextItemType = DisplayItem::nonCachedType(newIt->getType() ); 438 DisplayItem::Type nextItemType = DisplayItem::nonCachedType(newIt->getType() );
413 ++newIt; 439 ++newIt;
414 DCHECK(newIt->getType() == nextItemType); 440 DCHECK(newIt->getType() == nextItemType);
415 441
416 if (newIt->isDrawing()) { 442 if (newIt->isDrawing()) {
417 checkCachedDisplayItemIsUnchanged("", *newIt, *currentIt); 443 checkCachedDisplayItemIsUnchanged("", *newIt, *currentIt);
418 return; 444 return;
419 } 445 }
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
517 543
518 void PaintController::showDebugData() const 544 void PaintController::showDebugData() const
519 { 545 {
520 WTFLogAlways("current display item list: [%s]\n", displayItemListAsDebugStri ng(m_currentPaintArtifact.getDisplayItemList()).utf8().data()); 546 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()); 547 WTFLogAlways("new display item list: [%s]\n", displayItemListAsDebugString(m _newDisplayItemList).utf8().data());
522 } 548 }
523 549
524 #endif // ifndef NDEBUG 550 #endif // ifndef NDEBUG
525 551
526 } // namespace blink 552 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698