OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |