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

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

Powered by Google App Engine
This is Rietveld 408576698