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