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 | 10 |
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
131 #endif | 131 #endif |
132 | 132 |
133 invalidateUntracked(client); | 133 invalidateUntracked(client); |
134 if (RuntimeEnabledFeatures::slimmingPaintV2Enabled() && m_trackedPaintInvali
dationObjects) | 134 if (RuntimeEnabledFeatures::slimmingPaintV2Enabled() && m_trackedPaintInvali
dationObjects) |
135 m_trackedPaintInvalidationObjects->append(client.debugName()); | 135 m_trackedPaintInvalidationObjects->append(client.debugName()); |
136 } | 136 } |
137 | 137 |
138 void PaintController::invalidateUntracked(const DisplayItemClient& client) | 138 void PaintController::invalidateUntracked(const DisplayItemClient& client) |
139 { | 139 { |
140 // This can be called during painting, but we can't invalidate already paint
ed clients. | 140 // This can be called during painting, but we can't invalidate already paint
ed clients. |
| 141 client.setDisplayItemsCached(DisplayItemClient::kInvalidCacheGeneration); |
141 ASSERT(!m_newDisplayItemIndicesByClient.contains(&client)); | 142 ASSERT(!m_newDisplayItemIndicesByClient.contains(&client)); |
142 updateValidlyCachedClientsIfNeeded(); | |
143 m_validlyCachedClients.remove(&client); | |
144 } | 143 } |
145 | 144 |
146 void PaintController::invalidateAll() | 145 void PaintController::invalidateAll() |
147 { | 146 { |
148 // Can only be called during layout/paintInvalidation, not during painting. | 147 // Can only be called during layout/paintInvalidation, not during painting. |
149 ASSERT(m_newDisplayItemList.isEmpty()); | 148 ASSERT(m_newDisplayItemList.isEmpty()); |
150 m_currentPaintArtifact.reset(); | 149 m_currentPaintArtifact.reset(); |
151 m_validlyCachedClients.clear(); | 150 m_currentCacheGeneration = DisplayItemClient::kInvalidCacheGeneration; |
152 m_validlyCachedClientsDirty = false; | |
153 | 151 |
154 if (RuntimeEnabledFeatures::slimmingPaintV2Enabled() && m_trackedPaintInvali
dationObjects) | 152 if (RuntimeEnabledFeatures::slimmingPaintV2Enabled() && m_trackedPaintInvali
dationObjects) |
155 m_trackedPaintInvalidationObjects->append("##ALL##"); | 153 m_trackedPaintInvalidationObjects->append("##ALL##"); |
156 } | 154 } |
157 | 155 |
158 bool PaintController::clientCacheIsValid(const DisplayItemClient& client) const | 156 bool PaintController::clientCacheIsValid(const DisplayItemClient& client) const |
159 { | 157 { |
160 if (skippingCache()) | 158 ASSERT(DisplayItemClient::isAlive(client)); |
| 159 return DisplayItemClient::s_cacheStatus; |
| 160 #if 0 |
| 161 if (!canUseClientCacheStatus() || skippingCache()) |
161 return false; | 162 return false; |
162 updateValidlyCachedClientsIfNeeded(); | 163 return client.displayItemsAreCached(m_currentCacheGeneration); |
163 return m_validlyCachedClients.contains(&client); | 164 #endif |
164 } | 165 } |
165 | 166 |
166 void PaintController::invalidatePaintOffset(const DisplayItemClient& client) | 167 void PaintController::invalidatePaintOffset(const DisplayItemClient& client) |
167 { | 168 { |
168 ASSERT(RuntimeEnabledFeatures::slimmingPaintInvalidationEnabled()); | 169 ASSERT(RuntimeEnabledFeatures::slimmingPaintInvalidationEnabled()); |
169 invalidate(client); | 170 invalidate(client); |
170 | 171 |
171 #if ENABLE(ASSERT) | 172 #if ENABLE(ASSERT) |
172 ASSERT(!paintOffsetWasInvalidated(client)); | 173 ASSERT(!paintOffsetWasInvalidated(client)); |
173 m_clientsWithPaintOffsetInvalidations.add(&client); | 174 m_clientsWithPaintOffsetInvalidations.add(&client); |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
229 return findOutOfOrderCachedItemForward(id, context); | 230 return findOutOfOrderCachedItemForward(id, context); |
230 } | 231 } |
231 | 232 |
232 // Find forward for the item and index all skipped indexable items. | 233 // Find forward for the item and index all skipped indexable items. |
233 DisplayItemList::iterator PaintController::findOutOfOrderCachedItemForward(const
DisplayItem::Id& id, OutOfOrderIndexContext& context) | 234 DisplayItemList::iterator PaintController::findOutOfOrderCachedItemForward(const
DisplayItem::Id& id, OutOfOrderIndexContext& context) |
234 { | 235 { |
235 DisplayItemList::iterator currentEnd = m_currentPaintArtifact.getDisplayItem
List().end(); | 236 DisplayItemList::iterator currentEnd = m_currentPaintArtifact.getDisplayItem
List().end(); |
236 for (; context.nextItemToIndex != currentEnd; ++context.nextItemToIndex) { | 237 for (; context.nextItemToIndex != currentEnd; ++context.nextItemToIndex) { |
237 const DisplayItem& item = *context.nextItemToIndex; | 238 const DisplayItem& item = *context.nextItemToIndex; |
238 ASSERT(item.hasValidClient()); | 239 ASSERT(item.hasValidClient()); |
239 if (item.isCacheable() && clientCacheIsValid(item.client())) { | 240 if (id.matches(item)) |
240 if (id.matches(item)) | 241 return context.nextItemToIndex++; |
241 return context.nextItemToIndex++; | 242 if (item.isCacheable()) |
242 | |
243 addItemToIndexIfNeeded(item, context.nextItemToIndex - m_currentPain
tArtifact.getDisplayItemList().begin(), context.displayItemIndicesByClient); | 243 addItemToIndexIfNeeded(item, context.nextItemToIndex - m_currentPain
tArtifact.getDisplayItemList().begin(), context.displayItemIndicesByClient); |
244 } | |
245 } | 244 } |
246 return currentEnd; | 245 return currentEnd; |
247 } | 246 } |
248 | 247 |
249 void PaintController::copyCachedSubsequence(const DisplayItemList& currentList,
DisplayItemList::iterator& currentIt, DisplayItemList& updatedList) | 248 void PaintController::copyCachedSubsequence(const DisplayItemList& currentList,
DisplayItemList::iterator& currentIt, DisplayItemList& updatedList) |
250 { | 249 { |
251 ASSERT(currentIt->getType() == DisplayItem::Subsequence); | 250 ASSERT(currentIt->getType() == DisplayItem::Subsequence); |
252 ASSERT(!currentIt->scope()); | 251 ASSERT(!currentIt->scope()); |
253 DisplayItem::Id endSubsequenceId(currentIt->client(), DisplayItem::EndSubseq
uence, 0); | 252 DisplayItem::Id endSubsequenceId(currentIt->client(), DisplayItem::EndSubseq
uence, 0); |
254 do { | 253 do { |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
289 // Coefficients are related to the ratio of out-of-order CachedDisplayItems | 288 // Coefficients are related to the ratio of out-of-order CachedDisplayItems |
290 // and the average number of (Drawing|Subsequence)DisplayItems per client. | 289 // and the average number of (Drawing|Subsequence)DisplayItems per client. |
291 // | 290 // |
292 void PaintController::commitNewDisplayItemsInternal(const LayoutSize& offsetFrom
LayoutObject) | 291 void PaintController::commitNewDisplayItemsInternal(const LayoutSize& offsetFrom
LayoutObject) |
293 { | 292 { |
294 TRACE_EVENT2("blink,benchmark", "PaintController::commitNewDisplayItems", | 293 TRACE_EVENT2("blink,benchmark", "PaintController::commitNewDisplayItems", |
295 "current_display_list_size", (int)m_currentPaintArtifact.getDisplayItemL
ist().size(), | 294 "current_display_list_size", (int)m_currentPaintArtifact.getDisplayItemL
ist().size(), |
296 "num_non_cached_new_items", (int)m_newDisplayItemList.size() - m_numCach
edNewItems); | 295 "num_non_cached_new_items", (int)m_newDisplayItemList.size() - m_numCach
edNewItems); |
297 m_numCachedNewItems = 0; | 296 m_numCachedNewItems = 0; |
298 | 297 |
299 if (RuntimeEnabledFeatures::slimmingPaintV2Enabled()) | |
300 m_clientsCheckedPaintInvalidation.clear(); | |
301 | |
302 // These data structures are used during painting only. | 298 // These data structures are used during painting only. |
303 ASSERT(m_scopeStack.isEmpty()); | 299 ASSERT(m_scopeStack.isEmpty()); |
304 m_scopeStack.clear(); | 300 m_scopeStack.clear(); |
305 m_nextScope = 1; | 301 m_nextScope = 1; |
306 ASSERT(!skippingCache()); | 302 ASSERT(!skippingCache()); |
307 #if ENABLE(ASSERT) | 303 #if ENABLE(ASSERT) |
308 m_newDisplayItemIndicesByClient.clear(); | 304 m_newDisplayItemIndicesByClient.clear(); |
309 m_clientsWithPaintOffsetInvalidations.clear(); | 305 m_clientsWithPaintOffsetInvalidations.clear(); |
310 m_invalidations.clear(); | 306 m_invalidations.clear(); |
311 #endif | 307 #endif |
312 | 308 |
313 if (m_currentPaintArtifact.isEmpty()) { | 309 if (m_currentPaintArtifact.isEmpty()) { |
314 #if ENABLE(ASSERT) | 310 #if ENABLE(ASSERT) |
315 for (const auto& item : m_newDisplayItemList) | 311 for (const auto& item : m_newDisplayItemList) |
316 ASSERT(!item.isCached()); | 312 ASSERT(!item.isCached()); |
317 #endif | 313 #endif |
318 for (const auto& item : m_newDisplayItemList) | 314 for (const auto& item : m_newDisplayItemList) |
319 m_newDisplayItemList.appendVisualRect(visualRectForDisplayItem(item,
offsetFromLayoutObject)); | 315 m_newDisplayItemList.appendVisualRect(visualRectForDisplayItem(item,
offsetFromLayoutObject)); |
320 | 316 |
321 m_currentPaintArtifact = PaintArtifact(std::move(m_newDisplayItemList),
m_newPaintChunks.releasePaintChunks()); | 317 m_currentPaintArtifact = PaintArtifact(std::move(m_newDisplayItemList),
m_newPaintChunks.releasePaintChunks()); |
322 m_newDisplayItemList = DisplayItemList(kInitialDisplayItemListCapacityBy
tes); | 318 m_newDisplayItemList = DisplayItemList(kInitialDisplayItemListCapacityBy
tes); |
323 m_validlyCachedClientsDirty = true; | 319 updateCacheGeneration(); |
324 return; | 320 return; |
325 } | 321 } |
326 | 322 |
327 updateValidlyCachedClientsIfNeeded(); | |
328 | |
329 // Stores indices to valid DrawingDisplayItems in m_currentDisplayItems that
have not been matched | 323 // Stores indices to valid DrawingDisplayItems in m_currentDisplayItems that
have not been matched |
330 // by CachedDisplayItems during synchronized matching. The indexed items wil
l be matched | 324 // by CachedDisplayItems during synchronized matching. The indexed items wil
l be matched |
331 // by later out-of-order CachedDisplayItems in m_newDisplayItemList. This en
sures that when | 325 // by later out-of-order CachedDisplayItems in m_newDisplayItemList. This en
sures that when |
332 // out-of-order CachedDisplayItems occur, we only traverse at most once over
m_currentDisplayItems | 326 // out-of-order CachedDisplayItems occur, we only traverse at most once over
m_currentDisplayItems |
333 // looking for potential matches. Thus we can ensure that the algorithm runs
in linear time. | 327 // looking for potential matches. Thus we can ensure that the algorithm runs
in linear time. |
334 OutOfOrderIndexContext outOfOrderIndexContext(m_currentPaintArtifact.getDisp
layItemList().begin()); | 328 OutOfOrderIndexContext outOfOrderIndexContext(m_currentPaintArtifact.getDisp
layItemList().begin()); |
335 | 329 |
336 // TODO(jbroman): Consider revisiting this heuristic. | 330 // TODO(jbroman): Consider revisiting this heuristic. |
337 DisplayItemList updatedList(std::max(m_currentPaintArtifact.getDisplayItemLi
st().usedCapacityInBytes(), m_newDisplayItemList.usedCapacityInBytes())); | 331 DisplayItemList updatedList(std::max(m_currentPaintArtifact.getDisplayItemLi
st().usedCapacityInBytes(), m_newDisplayItemList.usedCapacityInBytes())); |
338 Vector<PaintChunk> updatedPaintChunks; | 332 Vector<PaintChunk> updatedPaintChunks; |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
396 #if ENABLE(ASSERT) | 390 #if ENABLE(ASSERT) |
397 if (RuntimeEnabledFeatures::slimmingPaintUnderInvalidationCheckingEnabled()) | 391 if (RuntimeEnabledFeatures::slimmingPaintUnderInvalidationCheckingEnabled()) |
398 checkNoRemainingCachedDisplayItems(); | 392 checkNoRemainingCachedDisplayItems(); |
399 #endif // ENABLE(ASSERT) | 393 #endif // ENABLE(ASSERT) |
400 | 394 |
401 // TODO(jbroman): When subsequence caching applies to SPv2, we'll need to | 395 // TODO(jbroman): When subsequence caching applies to SPv2, we'll need to |
402 // merge the paint chunks as well. | 396 // merge the paint chunks as well. |
403 m_currentPaintArtifact = PaintArtifact(std::move(updatedList), m_newPaintChu
nks.releasePaintChunks()); | 397 m_currentPaintArtifact = PaintArtifact(std::move(updatedList), m_newPaintChu
nks.releasePaintChunks()); |
404 | 398 |
405 m_newDisplayItemList = DisplayItemList(kInitialDisplayItemListCapacityBytes)
; | 399 m_newDisplayItemList = DisplayItemList(kInitialDisplayItemListCapacityBytes)
; |
406 m_validlyCachedClientsDirty = true; | 400 updateCacheGeneration(); |
407 } | 401 } |
408 | 402 |
409 size_t PaintController::approximateUnsharedMemoryUsage() const | 403 size_t PaintController::approximateUnsharedMemoryUsage() const |
410 { | 404 { |
411 size_t memoryUsage = sizeof(*this); | 405 size_t memoryUsage = sizeof(*this); |
412 | 406 |
413 // Memory outside this class due to m_currentPaintArtifact. | 407 // Memory outside this class due to m_currentPaintArtifact. |
414 memoryUsage += m_currentPaintArtifact.approximateUnsharedMemoryUsage() - siz
eof(m_currentPaintArtifact); | 408 memoryUsage += m_currentPaintArtifact.approximateUnsharedMemoryUsage() - siz
eof(m_currentPaintArtifact); |
415 | 409 |
416 // TODO(jbroman): If display items begin to have significant external memory | 410 // TODO(jbroman): If display items begin to have significant external memory |
417 // usage that's not shared with the embedder, we should account for it here. | 411 // usage that's not shared with the embedder, we should account for it here. |
418 // | 412 // |
419 // External objects, shared with the embedder, such as SkPicture, should be | 413 // External objects, shared with the embedder, such as SkPicture, should be |
420 // excluded to avoid double counting. It is the embedder's responsibility to | 414 // excluded to avoid double counting. It is the embedder's responsibility to |
421 // count such objects. | 415 // count such objects. |
422 // | 416 // |
423 // At time of writing, the only known case of unshared external memory was | 417 // At time of writing, the only known case of unshared external memory was |
424 // the rounded clips vector in ClipDisplayItem, which is not expected to | 418 // the rounded clips vector in ClipDisplayItem, which is not expected to |
425 // contribute significantly to memory usage. | 419 // contribute significantly to memory usage. |
426 | 420 |
427 // Memory outside this class due to m_newDisplayItemList. | 421 // Memory outside this class due to m_newDisplayItemList. |
428 ASSERT(m_newDisplayItemList.isEmpty()); | 422 ASSERT(m_newDisplayItemList.isEmpty()); |
429 memoryUsage += m_newDisplayItemList.memoryUsageInBytes(); | 423 memoryUsage += m_newDisplayItemList.memoryUsageInBytes(); |
430 | 424 |
431 return memoryUsage; | 425 return memoryUsage; |
432 } | 426 } |
433 | 427 |
434 void PaintController::updateValidlyCachedClientsIfNeeded() const | 428 unsigned PaintController::nextCacheGeneration() |
435 { | 429 { |
436 if (!m_validlyCachedClientsDirty) | 430 static unsigned cacheGeneration = DisplayItemClient::kInvalidCacheGeneration
; |
| 431 ++cacheGeneration; |
| 432 if (cacheGeneration == DisplayItemClient::kInvalidCacheGeneration) { |
| 433 // TODO(wangxianzhu): We'll reuse an old cache generation. Should invali
date all |
| 434 // clients that are still using the old generation. |
| 435 ++cacheGeneration; |
| 436 } |
| 437 return cacheGeneration; |
| 438 } |
| 439 |
| 440 void PaintController::updateCacheGeneration() |
| 441 { |
| 442 if (!canUseClientCacheStatus()) |
437 return; | 443 return; |
438 | 444 |
439 m_validlyCachedClients.clear(); | 445 m_currentCacheGeneration = nextCacheGeneration(); |
440 m_validlyCachedClientsDirty = false; | |
441 | |
442 const DisplayItemClient* lastAddedClient = nullptr; | |
443 for (const DisplayItem& displayItem : m_currentPaintArtifact.getDisplayItemL
ist()) { | 446 for (const DisplayItem& displayItem : m_currentPaintArtifact.getDisplayItemL
ist()) { |
444 if (&displayItem.client() == lastAddedClient) | 447 if (displayItem.isCacheable()) |
445 continue; | 448 displayItem.client().setDisplayItemsCached(m_currentCacheGeneration)
; |
446 if (displayItem.isCacheable()) { | |
447 lastAddedClient = &displayItem.client(); | |
448 m_validlyCachedClients.add(lastAddedClient); | |
449 } | |
450 } | 449 } |
451 } | 450 } |
452 | 451 |
453 #if ENABLE(ASSERT) | 452 #if ENABLE(ASSERT) |
454 | 453 |
455 void PaintController::checkUnderInvalidation(DisplayItemList::iterator& newIt, D
isplayItemList::iterator& currentIt) | 454 void PaintController::checkUnderInvalidation(DisplayItemList::iterator& newIt, D
isplayItemList::iterator& currentIt) |
456 { | 455 { |
457 ASSERT(RuntimeEnabledFeatures::slimmingPaintUnderInvalidationCheckingEnabled
()); | 456 ASSERT(RuntimeEnabledFeatures::slimmingPaintUnderInvalidationCheckingEnabled
()); |
458 ASSERT(newIt->isCached()); | 457 ASSERT(newIt->isCached()); |
459 | 458 |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
506 { | 505 { |
507 ASSERT(RuntimeEnabledFeatures::slimmingPaintUnderInvalidationCheckingEnabled
()); | 506 ASSERT(RuntimeEnabledFeatures::slimmingPaintUnderInvalidationCheckingEnabled
()); |
508 ASSERT(!newItem.isCached()); | 507 ASSERT(!newItem.isCached()); |
509 ASSERT(!oldItem.isCached()); | 508 ASSERT(!oldItem.isCached()); |
510 | 509 |
511 if (newItem.skippedCache()) { | 510 if (newItem.skippedCache()) { |
512 showUnderInvalidationError(messagePrefix, "ERROR: under-invalidation: sk
ipped-cache in cached subsequence", &newItem, &oldItem); | 511 showUnderInvalidationError(messagePrefix, "ERROR: under-invalidation: sk
ipped-cache in cached subsequence", &newItem, &oldItem); |
513 ASSERT_NOT_REACHED(); | 512 ASSERT_NOT_REACHED(); |
514 } | 513 } |
515 | 514 |
516 if (newItem.isCacheable() && !m_validlyCachedClients.contains(&newItem.clien
t())) { | 515 if (newItem.isCacheable() && !clientCacheIsValid(newItem.client())) { |
517 showUnderInvalidationError(messagePrefix, "ERROR: under-invalidation: in
validated in cached subsequence", &newItem, &oldItem); | 516 showUnderInvalidationError(messagePrefix, "ERROR: under-invalidation: in
validated in cached subsequence", &newItem, &oldItem); |
518 ASSERT_NOT_REACHED(); | 517 ASSERT_NOT_REACHED(); |
519 } | 518 } |
520 | 519 |
521 if (newItem.equals(oldItem)) | 520 if (newItem.equals(oldItem)) |
522 return; | 521 return; |
523 | 522 |
524 showUnderInvalidationError(messagePrefix, "ERROR: under-invalidation: displa
y item changed", &newItem, &oldItem); | 523 showUnderInvalidationError(messagePrefix, "ERROR: under-invalidation: displa
y item changed", &newItem, &oldItem); |
525 | 524 |
526 #ifndef NDEBUG | 525 #ifndef NDEBUG |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
573 | 572 |
574 void PaintController::showDebugData() const | 573 void PaintController::showDebugData() const |
575 { | 574 { |
576 WTFLogAlways("current display item list: [%s]\n", displayItemListAsDebugStri
ng(m_currentPaintArtifact.getDisplayItemList()).utf8().data()); | 575 WTFLogAlways("current display item list: [%s]\n", displayItemListAsDebugStri
ng(m_currentPaintArtifact.getDisplayItemList()).utf8().data()); |
577 WTFLogAlways("new display item list: [%s]\n", displayItemListAsDebugString(m
_newDisplayItemList).utf8().data()); | 576 WTFLogAlways("new display item list: [%s]\n", displayItemListAsDebugString(m
_newDisplayItemList).utf8().data()); |
578 } | 577 } |
579 | 578 |
580 #endif // ifndef NDEBUG | 579 #endif // ifndef NDEBUG |
581 | 580 |
582 } // namespace blink | 581 } // namespace blink |
OLD | NEW |