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