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 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
44 | 44 |
45 size_t cachedItem = findCachedItem(DisplayItem::Id(client, type)); | 45 size_t cachedItem = findCachedItem(DisplayItem::Id(client, type)); |
46 if (cachedItem == kNotFound) { | 46 if (cachedItem == kNotFound) { |
47 NOTREACHED(); | 47 NOTREACHED(); |
48 return false; | 48 return false; |
49 } | 49 } |
50 | 50 |
51 ++m_numCachedNewItems; | 51 ++m_numCachedNewItems; |
52 ensureNewDisplayItemListInitialCapacity(); | 52 ensureNewDisplayItemListInitialCapacity(); |
53 if (!DCHECK_IS_ON() || !RuntimeEnabledFeatures::slimmingPaintUnderInvalidati
onCheckingEnabled()) | 53 if (!DCHECK_IS_ON() || !RuntimeEnabledFeatures::slimmingPaintUnderInvalidati
onCheckingEnabled()) |
54 processNewItem(m_newDisplayItemList.appendByMoving(m_currentPaintArtifac
t.getDisplayItemList()[cachedItem])); | 54 processNewItem(m_newDisplayItemList.appendByMoving(m_currentPaintArtifac
t.getDisplayItemList()[cachedItem]), FromCachedItem); |
55 | 55 |
56 m_nextItemToMatch = cachedItem + 1; | 56 m_nextItemToMatch = cachedItem + 1; |
57 // Items before m_nextItemToMatch have been copied so we don't need to index
them. | 57 // Items before m_nextItemToMatch have been copied so we don't need to index
them. |
58 if (m_nextItemToMatch > m_nextItemToIndex) | 58 if (m_nextItemToMatch > m_nextItemToIndex) |
59 m_nextItemToIndex = m_nextItemToMatch; | 59 m_nextItemToIndex = m_nextItemToMatch; |
60 | 60 |
61 #if DCHECK_IS_ON() | 61 #if DCHECK_IS_ON() |
62 if (RuntimeEnabledFeatures::slimmingPaintUnderInvalidationCheckingEnabled())
{ | 62 if (RuntimeEnabledFeatures::slimmingPaintUnderInvalidationCheckingEnabled())
{ |
63 if (!isCheckingUnderInvalidation()) { | 63 if (!isCheckingUnderInvalidation()) { |
64 m_underInvalidationCheckingBegin = cachedItem; | 64 m_underInvalidationCheckingBegin = cachedItem; |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
126 return lastDisplayItem.isBegin() && !lastDisplayItem.drawsContent(); | 126 return lastDisplayItem.isBegin() && !lastDisplayItem.drawsContent(); |
127 } | 127 } |
128 | 128 |
129 void PaintController::removeLastDisplayItem() | 129 void PaintController::removeLastDisplayItem() |
130 { | 130 { |
131 if (m_newDisplayItemList.isEmpty()) | 131 if (m_newDisplayItemList.isEmpty()) |
132 return; | 132 return; |
133 | 133 |
134 #if DCHECK_IS_ON() | 134 #if DCHECK_IS_ON() |
135 // Also remove the index pointing to the removed display item. | 135 // Also remove the index pointing to the removed display item. |
136 DisplayItemIndicesByClientMap::iterator it = m_newDisplayItemIndicesByClient
.find(&m_newDisplayItemList.last().client()); | 136 IndicesByClientMap::iterator it = m_newDisplayItemIndicesByClient.find(&m_ne
wDisplayItemList.last().client()); |
137 if (it != m_newDisplayItemIndicesByClient.end()) { | 137 if (it != m_newDisplayItemIndicesByClient.end()) { |
138 Vector<size_t>& indices = it->value; | 138 Vector<size_t>& indices = it->value; |
139 if (!indices.isEmpty() && indices.last() == (m_newDisplayItemList.size()
- 1)) | 139 if (!indices.isEmpty() && indices.last() == (m_newDisplayItemList.size()
- 1)) |
140 indices.removeLast(); | 140 indices.removeLast(); |
141 } | 141 } |
142 | 142 |
143 if (RuntimeEnabledFeatures::slimmingPaintUnderInvalidationCheckingEnabled()
&& isCheckingUnderInvalidation()) { | 143 if (RuntimeEnabledFeatures::slimmingPaintUnderInvalidationCheckingEnabled()
&& isCheckingUnderInvalidation()) { |
144 if (m_skippedProbableUnderInvalidationCount) { | 144 if (m_skippedProbableUnderInvalidationCount) { |
145 --m_skippedProbableUnderInvalidationCount; | 145 --m_skippedProbableUnderInvalidationCount; |
146 } else { | 146 } else { |
147 DCHECK(m_underInvalidationCheckingBegin); | 147 DCHECK(m_underInvalidationCheckingBegin); |
148 --m_underInvalidationCheckingBegin; | 148 --m_underInvalidationCheckingBegin; |
149 } | 149 } |
150 } | 150 } |
151 #endif | 151 #endif |
152 m_newDisplayItemList.removeLast(); | 152 m_newDisplayItemList.removeLast(); |
153 | 153 |
154 if (RuntimeEnabledFeatures::slimmingPaintV2Enabled()) | 154 if (RuntimeEnabledFeatures::slimmingPaintV2Enabled()) |
155 m_newPaintChunks.decrementDisplayItemIndex(); | 155 m_newPaintChunks.decrementDisplayItemIndex(); |
156 } | 156 } |
157 | 157 |
158 const DisplayItem* PaintController::lastDisplayItem(unsigned offset) | 158 const DisplayItem* PaintController::lastDisplayItem(unsigned offset) |
159 { | 159 { |
160 if (offset < m_newDisplayItemList.size()) | 160 if (offset < m_newDisplayItemList.size()) |
161 return &m_newDisplayItemList[m_newDisplayItemList.size() - offset - 1]; | 161 return &m_newDisplayItemList[m_newDisplayItemList.size() - offset - 1]; |
162 return nullptr; | 162 return nullptr; |
163 } | 163 } |
164 | 164 |
165 void PaintController::processNewItem(DisplayItem& displayItem) | 165 void PaintController::processNewItem(DisplayItem& displayItem, NewItemSource new
ItemSource) |
166 { | 166 { |
167 DCHECK(!m_constructionDisabled); | 167 DCHECK(!m_constructionDisabled); |
168 | 168 |
169 #if CHECK_DISPLAY_ITEM_CLIENT_ALIVENESS | 169 #if CHECK_DISPLAY_ITEM_CLIENT_ALIVENESS |
170 if (!isSkippingCache()) { | 170 if (!isSkippingCache()) { |
171 if (displayItem.isCacheable()) { | 171 if (displayItem.isCacheable()) { |
172 // Mark the client shouldKeepAlive under this PaintController. | 172 // Mark the client shouldKeepAlive under this PaintController. |
173 // The status will end after the new display items are committed. | 173 // The status will end after the new display items are committed. |
174 displayItem.client().beginShouldKeepAlive(this); | 174 displayItem.client().beginShouldKeepAlive(this); |
175 | 175 |
176 if (!m_currentSubsequenceClients.isEmpty()) { | 176 if (!m_currentSubsequenceClients.isEmpty()) { |
177 // Mark the client shouldKeepAlive under the current subsequence
. | 177 // Mark the client shouldKeepAlive under the current subsequence
. |
178 // The status will end when the subsequence owner is invalidated
or deleted. | 178 // The status will end when the subsequence owner is invalidated
or deleted. |
179 displayItem.client().beginShouldKeepAlive(m_currentSubsequenceCl
ients.last()); | 179 displayItem.client().beginShouldKeepAlive(m_currentSubsequenceCl
ients.last()); |
180 } | 180 } |
181 } | 181 } |
182 | 182 |
183 if (displayItem.getType() == DisplayItem::Subsequence) { | 183 if (displayItem.getType() == DisplayItem::Subsequence) { |
184 m_currentSubsequenceClients.append(&displayItem.client()); | 184 m_currentSubsequenceClients.append(&displayItem.client()); |
185 } else if (displayItem.getType() == DisplayItem::EndSubsequence) { | 185 } else if (displayItem.getType() == DisplayItem::EndSubsequence) { |
186 CHECK(m_currentSubsequenceClients.last() == &displayItem.client()); | 186 CHECK(m_currentSubsequenceClients.last() == &displayItem.client()); |
187 m_currentSubsequenceClients.removeLast(); | 187 m_currentSubsequenceClients.removeLast(); |
188 } | 188 } |
189 } | 189 } |
190 #endif | 190 #endif |
191 | 191 |
192 if (isSkippingCache()) | 192 if (isSkippingCache()) { |
| 193 DCHECK(newItemSource == NewPainting); |
193 displayItem.setSkippedCache(); | 194 displayItem.setSkippedCache(); |
| 195 } |
| 196 |
| 197 if (RuntimeEnabledFeatures::slimmingPaintV2Enabled()) { |
| 198 if (newItemSource != FromCachedSubsequence) |
| 199 m_currentChunkIsFromCachedSubsequence = false; |
| 200 |
| 201 size_t lastChunkIndex = m_newPaintChunks.lastChunkIndex(); |
| 202 if (m_newPaintChunks.incrementDisplayItemIndex(displayItem)) { |
| 203 DCHECK(lastChunkIndex != m_newPaintChunks.lastChunkIndex()); |
| 204 if (lastChunkIndex != kNotFound) |
| 205 generateChunkRasterInvalidationRects(m_newPaintChunks.paintChunk
At(lastChunkIndex)); |
| 206 m_currentChunkIsFromCachedSubsequence = true; |
| 207 } |
| 208 } |
194 | 209 |
195 #if DCHECK_IS_ON() | 210 #if DCHECK_IS_ON() |
196 // Verify noop begin/end pairs have been removed. | 211 // Verify noop begin/end pairs have been removed. |
197 if (m_newDisplayItemList.size() >= 2 && displayItem.isEnd()) { | 212 if (m_newDisplayItemList.size() >= 2 && displayItem.isEnd()) { |
198 const auto& beginDisplayItem = m_newDisplayItemList[m_newDisplayItemList
.size() - 2]; | 213 const auto& beginDisplayItem = m_newDisplayItemList[m_newDisplayItemList
.size() - 2]; |
199 if (beginDisplayItem.isBegin() && beginDisplayItem.getType() != DisplayI
tem::Subsequence && !beginDisplayItem.drawsContent()) | 214 if (beginDisplayItem.isBegin() && beginDisplayItem.getType() != DisplayI
tem::Subsequence && !beginDisplayItem.drawsContent()) |
200 DCHECK(!displayItem.isEndAndPairedWith(beginDisplayItem.getType())); | 215 DCHECK(!displayItem.isEndAndPairedWith(beginDisplayItem.getType())); |
201 } | 216 } |
202 | 217 |
203 size_t index = findMatchingItemFromIndex(displayItem.getId(), m_newDisplayIt
emIndicesByClient, m_newDisplayItemList); | 218 size_t index = findMatchingItemFromIndex(displayItem.getId(), m_newDisplayIt
emIndicesByClient, m_newDisplayItemList); |
204 if (index != kNotFound) { | 219 if (index != kNotFound) { |
205 #ifndef NDEBUG | 220 #ifndef NDEBUG |
206 showDebugData(); | 221 showDebugData(); |
207 WTFLogAlways("DisplayItem %s has duplicated id with previous %s (index=%
d)\n", | 222 WTFLogAlways("DisplayItem %s has duplicated id with previous %s (index=%
d)\n", |
208 displayItem.asDebugString().utf8().data(), m_newDisplayItemList[inde
x].asDebugString().utf8().data(), static_cast<int>(index)); | 223 displayItem.asDebugString().utf8().data(), m_newDisplayItemList[inde
x].asDebugString().utf8().data(), static_cast<int>(index)); |
209 #endif | 224 #endif |
210 NOTREACHED(); | 225 NOTREACHED(); |
211 } | 226 } |
212 addItemToIndexIfNeeded(displayItem, m_newDisplayItemList.size() - 1, m_newDi
splayItemIndicesByClient); | 227 addItemToIndexIfNeeded(displayItem, m_newDisplayItemList.size() - 1, m_newDi
splayItemIndicesByClient); |
213 | 228 |
214 if (RuntimeEnabledFeatures::slimmingPaintUnderInvalidationCheckingEnabled()) | 229 if (RuntimeEnabledFeatures::slimmingPaintUnderInvalidationCheckingEnabled()) |
215 checkUnderInvalidation(); | 230 checkUnderInvalidation(); |
216 #endif // DCHECK_IS_ON() | 231 #endif // DCHECK_IS_ON() |
217 | |
218 if (RuntimeEnabledFeatures::slimmingPaintV2Enabled()) | |
219 m_newPaintChunks.incrementDisplayItemIndex(displayItem); | |
220 } | 232 } |
221 | 233 |
222 void PaintController::updateCurrentPaintChunkProperties(const PaintChunk::Id* id
, const PaintChunkProperties& newProperties) | 234 void PaintController::updateCurrentPaintChunkProperties(const PaintChunk::Id* id
, const PaintChunkProperties& newProperties) |
223 { | 235 { |
224 m_newPaintChunks.updateCurrentPaintChunkProperties(id, newProperties); | 236 m_newPaintChunks.updateCurrentPaintChunkProperties(id, newProperties); |
225 } | 237 } |
226 | 238 |
227 const PaintChunkProperties& PaintController::currentPaintChunkProperties() const | 239 const PaintChunkProperties& PaintController::currentPaintChunkProperties() const |
228 { | 240 { |
229 return m_newPaintChunks.currentPaintChunkProperties(); | 241 return m_newPaintChunks.currentPaintChunkProperties(); |
(...skipping 10 matching lines...) Expand all Loading... |
240 bool PaintController::clientCacheIsValid(const DisplayItemClient& client) const | 252 bool PaintController::clientCacheIsValid(const DisplayItemClient& client) const |
241 { | 253 { |
242 #if CHECK_DISPLAY_ITEM_CLIENT_ALIVENESS | 254 #if CHECK_DISPLAY_ITEM_CLIENT_ALIVENESS |
243 CHECK(client.isAlive()); | 255 CHECK(client.isAlive()); |
244 #endif | 256 #endif |
245 if (isSkippingCache()) | 257 if (isSkippingCache()) |
246 return false; | 258 return false; |
247 return client.displayItemsAreCached(m_currentCacheGeneration); | 259 return client.displayItemsAreCached(m_currentCacheGeneration); |
248 } | 260 } |
249 | 261 |
250 size_t PaintController::findMatchingItemFromIndex(const DisplayItem::Id& id, con
st DisplayItemIndicesByClientMap& displayItemIndicesByClient, const DisplayItemL
ist& list) | 262 size_t PaintController::findMatchingItemFromIndex(const DisplayItem::Id& id, con
st IndicesByClientMap& displayItemIndicesByClient, const DisplayItemList& list) |
251 { | 263 { |
252 DisplayItemIndicesByClientMap::const_iterator it = displayItemIndicesByClien
t.find(&id.client); | 264 IndicesByClientMap::const_iterator it = displayItemIndicesByClient.find(&id.
client); |
253 if (it == displayItemIndicesByClient.end()) | 265 if (it == displayItemIndicesByClient.end()) |
254 return kNotFound; | 266 return kNotFound; |
255 | 267 |
256 const Vector<size_t>& indices = it->value; | 268 const Vector<size_t>& indices = it->value; |
257 for (size_t index : indices) { | 269 for (size_t index : indices) { |
258 const DisplayItem& existingItem = list[index]; | 270 const DisplayItem& existingItem = list[index]; |
259 DCHECK(!existingItem.hasValidClient() || existingItem.client() == id.cli
ent); | 271 DCHECK(!existingItem.hasValidClient() || existingItem.client() == id.cli
ent); |
260 if (id == existingItem.getId()) | 272 if (id == existingItem.getId()) |
261 return index; | 273 return index; |
262 } | 274 } |
263 | 275 |
264 return kNotFound; | 276 return kNotFound; |
265 } | 277 } |
266 | 278 |
267 void PaintController::addItemToIndexIfNeeded(const DisplayItem& displayItem, siz
e_t index, DisplayItemIndicesByClientMap& displayItemIndicesByClient) | 279 void PaintController::addItemToIndexIfNeeded(const DisplayItem& displayItem, siz
e_t index, IndicesByClientMap& displayItemIndicesByClient) |
268 { | 280 { |
269 if (!displayItem.isCacheable()) | 281 if (!displayItem.isCacheable()) |
270 return; | 282 return; |
271 | 283 |
272 DisplayItemIndicesByClientMap::iterator it = displayItemIndicesByClient.find
(&displayItem.client()); | 284 IndicesByClientMap::iterator it = displayItemIndicesByClient.find(&displayIt
em.client()); |
273 Vector<size_t>& indices = it == displayItemIndicesByClient.end() ? | 285 Vector<size_t>& indices = it == displayItemIndicesByClient.end() ? |
274 displayItemIndicesByClient.add(&displayItem.client(), Vector<size_t>()).
storedValue->value : it->value; | 286 displayItemIndicesByClient.add(&displayItem.client(), Vector<size_t>()).
storedValue->value : it->value; |
275 indices.append(index); | 287 indices.append(index); |
276 } | 288 } |
277 | 289 |
278 size_t PaintController::findCachedItem(const DisplayItem::Id& id) | 290 size_t PaintController::findCachedItem(const DisplayItem::Id& id) |
279 { | 291 { |
280 DCHECK(clientCacheIsValid(id.client)); | 292 DCHECK(clientCacheIsValid(id.client)); |
281 | 293 |
282 // Try to find the item sequentially first. This is fast if the current list
and the new list are in | 294 // Try to find the item sequentially first. This is fast if the current list
and the new list are in |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
370 #if CHECK_DISPLAY_ITEM_CLIENT_ALIVENESS | 382 #if CHECK_DISPLAY_ITEM_CLIENT_ALIVENESS |
371 CHECK(cachedItem->client().isAlive()); | 383 CHECK(cachedItem->client().isAlive()); |
372 #endif | 384 #endif |
373 ++m_numCachedNewItems; | 385 ++m_numCachedNewItems; |
374 bool metEndSubsequence = cachedItem->getId() == endSubsequenceId; | 386 bool metEndSubsequence = cachedItem->getId() == endSubsequenceId; |
375 if (!DCHECK_IS_ON() || !RuntimeEnabledFeatures::slimmingPaintUnderInvali
dationCheckingEnabled()) { | 387 if (!DCHECK_IS_ON() || !RuntimeEnabledFeatures::slimmingPaintUnderInvali
dationCheckingEnabled()) { |
376 if (RuntimeEnabledFeatures::slimmingPaintV2Enabled() && cachedItemIn
dex == cachedChunk->endIndex) { | 388 if (RuntimeEnabledFeatures::slimmingPaintV2Enabled() && cachedItemIn
dex == cachedChunk->endIndex) { |
377 ++cachedChunk; | 389 ++cachedChunk; |
378 updateCurrentPaintChunkProperties(cachedChunk->id ? &*cachedChun
k->id : nullptr, cachedChunk->properties); | 390 updateCurrentPaintChunkProperties(cachedChunk->id ? &*cachedChun
k->id : nullptr, cachedChunk->properties); |
379 } | 391 } |
380 processNewItem(m_newDisplayItemList.appendByMoving(*cachedItem)); | 392 processNewItem(m_newDisplayItemList.appendByMoving(*cachedItem), Fro
mCachedSubsequence); |
381 if (RuntimeEnabledFeatures::slimmingPaintV2Enabled()) | 393 if (RuntimeEnabledFeatures::slimmingPaintV2Enabled()) |
382 DCHECK((!m_newPaintChunks.lastChunk().id && !cachedChunk->id) ||
m_newPaintChunks.lastChunk().matches(*cachedChunk)); | 394 DCHECK((!m_newPaintChunks.lastChunk().id && !cachedChunk->id) ||
m_newPaintChunks.lastChunk().matches(*cachedChunk)); |
383 } | 395 } |
384 | 396 |
385 ++cachedItemIndex; | 397 ++cachedItemIndex; |
386 if (metEndSubsequence) | 398 if (metEndSubsequence) |
387 break; | 399 break; |
388 | 400 |
389 // We should always be able to find the EndSubsequence display item. | 401 // We should always be able to find the EndSubsequence display item. |
390 DCHECK(cachedItemIndex < m_currentPaintArtifact.getDisplayItemList().siz
e()); | 402 DCHECK(cachedItemIndex < m_currentPaintArtifact.getDisplayItemList().siz
e()); |
(...skipping 12 matching lines...) Expand all Loading... |
403 { | 415 { |
404 LayoutRect visualRect = displayItem.client().visualRect(); | 416 LayoutRect visualRect = displayItem.client().visualRect(); |
405 visualRect.move(-offsetFromLayoutObject); | 417 visualRect.move(-offsetFromLayoutObject); |
406 return enclosingIntRect(visualRect); | 418 return enclosingIntRect(visualRect); |
407 } | 419 } |
408 | 420 |
409 void PaintController::resetCurrentListIndices() | 421 void PaintController::resetCurrentListIndices() |
410 { | 422 { |
411 m_nextItemToMatch = 0; | 423 m_nextItemToMatch = 0; |
412 m_nextItemToIndex = 0; | 424 m_nextItemToIndex = 0; |
| 425 m_nextChunkToMatch = 0; |
413 #if DCHECK_IS_ON() | 426 #if DCHECK_IS_ON() |
414 m_underInvalidationCheckingBegin = 0; | 427 m_underInvalidationCheckingBegin = 0; |
415 m_underInvalidationCheckingEnd = 0; | 428 m_underInvalidationCheckingEnd = 0; |
416 m_skippedProbableUnderInvalidationCount = 0; | 429 m_skippedProbableUnderInvalidationCount = 0; |
417 #endif | 430 #endif |
418 } | 431 } |
419 | 432 |
420 void PaintController::commitNewDisplayItems(const LayoutSize& offsetFromLayoutOb
ject) | 433 void PaintController::commitNewDisplayItems(const LayoutSize& offsetFromLayoutOb
ject) |
421 { | 434 { |
422 TRACE_EVENT2("blink,benchmark", "PaintController::commitNewDisplayItems", | 435 TRACE_EVENT2("blink,benchmark", "PaintController::commitNewDisplayItems", |
423 "current_display_list_size", (int)m_currentPaintArtifact.getDisplayItemL
ist().size(), | 436 "current_display_list_size", (int)m_currentPaintArtifact.getDisplayItemL
ist().size(), |
424 "num_non_cached_new_items", (int)m_newDisplayItemList.size() - m_numCach
edNewItems); | 437 "num_non_cached_new_items", (int)m_newDisplayItemList.size() - m_numCach
edNewItems); |
425 m_numCachedNewItems = 0; | 438 m_numCachedNewItems = 0; |
426 | 439 |
427 // These data structures are used during painting only. | 440 // These data structures are used during painting only. |
428 DCHECK(!isSkippingCache()); | 441 DCHECK(!isSkippingCache()); |
429 #if DCHECK_IS_ON() | 442 #if DCHECK_IS_ON() |
430 m_newDisplayItemIndicesByClient.clear(); | 443 m_newDisplayItemIndicesByClient.clear(); |
431 #endif | 444 #endif |
432 | 445 |
| 446 if (RuntimeEnabledFeatures::slimmingPaintV2Enabled() && !m_newDisplayItemLis
t.isEmpty()) |
| 447 generateChunkRasterInvalidationRects(m_newPaintChunks.lastChunk()); |
| 448 |
433 SkPictureGpuAnalyzer gpuAnalyzer; | 449 SkPictureGpuAnalyzer gpuAnalyzer; |
434 | 450 |
435 m_currentCacheGeneration = DisplayItemClient::CacheGenerationOrInvalidationR
eason::next(); | 451 m_currentCacheGeneration = DisplayItemClient::CacheGenerationOrInvalidationR
eason::next(); |
436 Vector<const DisplayItemClient*> skippedCacheClients; | 452 Vector<const DisplayItemClient*> skippedCacheClients; |
437 for (const auto& item : m_newDisplayItemList) { | 453 for (const auto& item : m_newDisplayItemList) { |
438 // No reason to continue the analysis once we have a veto. | 454 // No reason to continue the analysis once we have a veto. |
439 if (gpuAnalyzer.suitableForGpuRasterization()) | 455 if (gpuAnalyzer.suitableForGpuRasterization()) |
440 item.analyzeForGpuRasterization(gpuAnalyzer); | 456 item.analyzeForGpuRasterization(gpuAnalyzer); |
441 | 457 |
442 // TODO(wkorman): Only compute and append visual rect for drawings. | 458 // TODO(wkorman): Only compute and append visual rect for drawings. |
(...skipping 10 matching lines...) Expand all Loading... |
453 } | 469 } |
454 | 470 |
455 for (auto* client : skippedCacheClients) | 471 for (auto* client : skippedCacheClients) |
456 client->setDisplayItemsUncached(); | 472 client->setDisplayItemsUncached(); |
457 | 473 |
458 // The new list will not be appended to again so we can release unused memor
y. | 474 // The new list will not be appended to again so we can release unused memor
y. |
459 m_newDisplayItemList.shrinkToFit(); | 475 m_newDisplayItemList.shrinkToFit(); |
460 m_currentPaintArtifact = PaintArtifact(std::move(m_newDisplayItemList), m_ne
wPaintChunks.releasePaintChunks(), gpuAnalyzer.suitableForGpuRasterization()); | 476 m_currentPaintArtifact = PaintArtifact(std::move(m_newDisplayItemList), m_ne
wPaintChunks.releasePaintChunks(), gpuAnalyzer.suitableForGpuRasterization()); |
461 resetCurrentListIndices(); | 477 resetCurrentListIndices(); |
462 m_outOfOrderItemIndices.clear(); | 478 m_outOfOrderItemIndices.clear(); |
| 479 m_outOfOrderChunkIndices.clear(); |
463 | 480 |
464 if (RuntimeEnabledFeatures::slimmingPaintV2Enabled()) { | 481 if (RuntimeEnabledFeatures::slimmingPaintV2Enabled()) { |
465 for (const auto& chunk : m_currentPaintArtifact.paintChunks()) { | 482 for (const auto& chunk : m_currentPaintArtifact.paintChunks()) { |
466 if (chunk.id && chunk.id->client.isJustCreated()) | 483 if (chunk.id && chunk.id->client.isJustCreated()) |
467 chunk.id->client.clearIsJustCreated(); | 484 chunk.id->client.clearIsJustCreated(); |
468 } | 485 } |
469 } | 486 } |
470 | 487 |
471 // We'll allocate the initial buffer when we start the next paint. | 488 // We'll allocate the initial buffer when we start the next paint. |
472 m_newDisplayItemList = DisplayItemList(0); | 489 m_newDisplayItemList = DisplayItemList(0); |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
510 | 527 |
511 void PaintController::appendDebugDrawingAfterCommit(const DisplayItemClient& dis
playItemClient, PassRefPtr<SkPicture> picture, const LayoutSize& offsetFromLayou
tObject) | 528 void PaintController::appendDebugDrawingAfterCommit(const DisplayItemClient& dis
playItemClient, PassRefPtr<SkPicture> picture, const LayoutSize& offsetFromLayou
tObject) |
512 { | 529 { |
513 DCHECK(m_newDisplayItemList.isEmpty()); | 530 DCHECK(m_newDisplayItemList.isEmpty()); |
514 DrawingDisplayItem& displayItem = m_currentPaintArtifact.getDisplayItemList(
).allocateAndConstruct<DrawingDisplayItem>(displayItemClient, DisplayItem::Debug
Drawing, picture); | 531 DrawingDisplayItem& displayItem = m_currentPaintArtifact.getDisplayItemList(
).allocateAndConstruct<DrawingDisplayItem>(displayItemClient, DisplayItem::Debug
Drawing, picture); |
515 displayItem.setSkippedCache(); | 532 displayItem.setSkippedCache(); |
516 // TODO(wkorman): Only compute and append visual rect for drawings. | 533 // TODO(wkorman): Only compute and append visual rect for drawings. |
517 m_currentPaintArtifact.getDisplayItemList().appendVisualRect(visualRectForDi
splayItem(displayItem, offsetFromLayoutObject)); | 534 m_currentPaintArtifact.getDisplayItemList().appendVisualRect(visualRectForDi
splayItem(displayItem, offsetFromLayoutObject)); |
518 } | 535 } |
519 | 536 |
| 537 void PaintController::generateChunkRasterInvalidationRects(PaintChunk& newChunk) |
| 538 { |
| 539 DCHECK(RuntimeEnabledFeatures::slimmingPaintV2Enabled()); |
| 540 if (m_currentChunkIsFromCachedSubsequence) |
| 541 return; |
| 542 |
| 543 if (!newChunk.id) { |
| 544 newChunk.rasterInvalidationRects.append(FloatRect(LayoutRect::infiniteIn
tRect())); |
| 545 return; |
| 546 } |
| 547 |
| 548 // Try to match old chunk sequentially first. |
| 549 const auto& oldChunks = m_currentPaintArtifact.paintChunks(); |
| 550 while (m_nextChunkToMatch < oldChunks.size()) { |
| 551 const PaintChunk& oldChunk = oldChunks[m_nextChunkToMatch]; |
| 552 if (newChunk.matches(oldChunk)) { |
| 553 generateChunkRasterInvalidationRectsComparingOldChunk(newChunk, oldC
hunk); |
| 554 ++m_nextChunkToMatch; |
| 555 return; |
| 556 } |
| 557 |
| 558 // Add skipped old chunks into the index. |
| 559 if (oldChunk.id) { |
| 560 auto it = m_outOfOrderChunkIndices.find(&oldChunk.id->client); |
| 561 Vector<size_t>& indices = it == m_outOfOrderChunkIndices.end() ? |
| 562 m_outOfOrderChunkIndices.add(&oldChunk.id->client, Vector<size_t
>()).storedValue->value : it->value; |
| 563 indices.append(m_nextChunkToMatch); |
| 564 } |
| 565 ++m_nextChunkToMatch; |
| 566 } |
| 567 |
| 568 // Sequential matching reaches the end. Find from the out-of-order index. |
| 569 auto it = m_outOfOrderChunkIndices.find(&newChunk.id->client); |
| 570 if (it != m_outOfOrderChunkIndices.end()) { |
| 571 for (size_t i : it->value) { |
| 572 if (newChunk.matches(oldChunks[i])) { |
| 573 generateChunkRasterInvalidationRectsComparingOldChunk(newChunk,
oldChunks[i]); |
| 574 return; |
| 575 } |
| 576 } |
| 577 } |
| 578 |
| 579 // We reach here because the chunk is new. |
| 580 newChunk.rasterInvalidationRects.append(FloatRect(LayoutRect::infiniteIntRec
t())); |
| 581 } |
| 582 |
| 583 void PaintController::generateChunkRasterInvalidationRectsComparingOldChunk(Pain
tChunk& newChunk, const PaintChunk& oldChunk) |
| 584 { |
| 585 DCHECK(RuntimeEnabledFeatures::slimmingPaintV2Enabled()); |
| 586 |
| 587 // TODO(wangxianzhu): Support raster invalidation for reordered display item
s without invalidating |
| 588 // display item clients. Currently we invalidate display item clients ensuri
ng raster invalidation. |
| 589 // TODO(wangxianzhu): Handle PaintInvalidationIncremental. |
| 590 // TODO(wangxianzhu): Optimize paint offset change. |
| 591 |
| 592 // Maps from each client to the index of the first drawing-content display i
tem of the client. |
| 593 HashMap<const DisplayItemClient*, size_t> oldChunkClients; |
| 594 for (size_t i = oldChunk.beginIndex; i < oldChunk.endIndex; ++i) { |
| 595 const DisplayItem& oldItem = m_currentPaintArtifact.getDisplayItemList()
[i]; |
| 596 // oldItem.hasValidClient() indicates that the item has not been copied
as a cached item into |
| 597 // m_newDislayItemList, so the item either disappeared or changed, and n
eeds raster invalidation. |
| 598 if (oldItem.hasValidClient() && oldItem.drawsContent() && oldChunkClient
s.add(&oldItem.client(), i).isNewEntry) |
| 599 newChunk.rasterInvalidationRects.append(m_currentPaintArtifact.getDi
splayItemList().visualRect(i)); |
| 600 } |
| 601 |
| 602 HashSet<const DisplayItemClient*> newChunkClients; |
| 603 for (size_t i = newChunk.beginIndex; i < newChunk.endIndex; ++i) { |
| 604 const DisplayItem& newItem = m_newDisplayItemList[i]; |
| 605 if (newItem.drawsContent()) { |
| 606 if (!clientCacheIsValid(newItem.client())) { |
| 607 if (newChunkClients.add(&newItem.client()).isNewEntry) |
| 608 newChunk.rasterInvalidationRects.append(newItem.client().vis
ualRect()); |
| 609 } else { |
| 610 // The cached item was moved from the old chunk which should not
contain any item of the client now. |
| 611 DCHECK(!oldChunkClients.contains(&newItem.client())); |
| 612 } |
| 613 } |
| 614 } |
| 615 } |
| 616 |
520 #if DCHECK_IS_ON() | 617 #if DCHECK_IS_ON() |
521 | 618 |
522 void PaintController::showUnderInvalidationError(const char* reason, const Displ
ayItem& newItem, const DisplayItem* oldItem) const | 619 void PaintController::showUnderInvalidationError(const char* reason, const Displ
ayItem& newItem, const DisplayItem* oldItem) const |
523 { | 620 { |
524 LOG(ERROR) << m_underInvalidationMessagePrefix << " " << reason; | 621 LOG(ERROR) << m_underInvalidationMessagePrefix << " " << reason; |
525 #ifndef NDEBUG | 622 #ifndef NDEBUG |
526 LOG(ERROR) << "New display item: " << newItem.asDebugString(); | 623 LOG(ERROR) << "New display item: " << newItem.asDebugString(); |
527 LOG(ERROR) << "Old display item: " << (oldItem ? oldItem->asDebugString() :
"None"); | 624 LOG(ERROR) << "Old display item: " << (oldItem ? oldItem->asDebugString() :
"None"); |
528 #else | 625 #else |
529 LOG(ERROR) << "Run debug build to get more details."; | 626 LOG(ERROR) << "Run debug build to get more details."; |
(...skipping 12 matching lines...) Expand all Loading... |
542 | 639 |
543 void PaintController::checkUnderInvalidation() | 640 void PaintController::checkUnderInvalidation() |
544 { | 641 { |
545 DCHECK(RuntimeEnabledFeatures::slimmingPaintUnderInvalidationCheckingEnabled
()); | 642 DCHECK(RuntimeEnabledFeatures::slimmingPaintUnderInvalidationCheckingEnabled
()); |
546 | 643 |
547 if (!isCheckingUnderInvalidation()) | 644 if (!isCheckingUnderInvalidation()) |
548 return; | 645 return; |
549 | 646 |
550 const DisplayItem& newItem = m_newDisplayItemList.last(); | 647 const DisplayItem& newItem = m_newDisplayItemList.last(); |
551 size_t oldItemIndex = m_underInvalidationCheckingBegin + m_skippedProbableUn
derInvalidationCount; | 648 size_t oldItemIndex = m_underInvalidationCheckingBegin + m_skippedProbableUn
derInvalidationCount; |
552 const DisplayItem* oldItem = oldItemIndex < m_currentPaintArtifact.getDispla
yItemList().size() ? &m_currentPaintArtifact.getDisplayItemList()[oldItemIndex]
: nullptr; | 649 DisplayItem* oldItem = oldItemIndex < m_currentPaintArtifact.getDisplayItemL
ist().size() ? &m_currentPaintArtifact.getDisplayItemList()[oldItemIndex] : null
ptr; |
553 | 650 |
554 bool oldAndNewEqual = oldItem && newItem.equals(*oldItem); | 651 bool oldAndNewEqual = oldItem && newItem.equals(*oldItem); |
555 if (!oldAndNewEqual) { | 652 if (!oldAndNewEqual) { |
556 if (newItem.isBegin()) { | 653 if (newItem.isBegin()) { |
557 // Temporarily skip mismatching begin display item which may be remo
ved when we remove a no-op pair. | 654 // Temporarily skip mismatching begin display item which may be remo
ved when we remove a no-op pair. |
558 ++m_skippedProbableUnderInvalidationCount; | 655 ++m_skippedProbableUnderInvalidationCount; |
559 return; | 656 return; |
560 } | 657 } |
561 if (newItem.isDrawing() && m_skippedProbableUnderInvalidationCount == 1)
{ | 658 if (newItem.isDrawing() && m_skippedProbableUnderInvalidationCount == 1)
{ |
562 DCHECK_GE(m_newDisplayItemList.size(), 2u); | 659 DCHECK_GE(m_newDisplayItemList.size(), 2u); |
563 if (m_newDisplayItemList[m_newDisplayItemList.size() - 2].getType()
== DisplayItem::BeginCompositing) { | 660 if (m_newDisplayItemList[m_newDisplayItemList.size() - 2].getType()
== DisplayItem::BeginCompositing) { |
564 // This might be a drawing item between a pair of begin/end comp
ositing display items that will be folded | 661 // This might be a drawing item between a pair of begin/end comp
ositing display items that will be folded |
565 // into a single drawing display item. | 662 // into a single drawing display item. |
566 ++m_skippedProbableUnderInvalidationCount; | 663 ++m_skippedProbableUnderInvalidationCount; |
567 return; | 664 return; |
568 } | 665 } |
569 } | 666 } |
570 } | 667 } |
571 | 668 |
572 if (m_skippedProbableUnderInvalidationCount || !oldAndNewEqual) { | 669 if (m_skippedProbableUnderInvalidationCount || !oldAndNewEqual) { |
573 // If we ever skipped reporting any under-invalidations, report the earl
iest one. | 670 // If we ever skipped reporting any under-invalidations, report the earl
iest one. |
574 showUnderInvalidationError("under-invalidation: display item changed", | 671 showUnderInvalidationError("under-invalidation: display item changed", |
575 m_newDisplayItemList[m_newDisplayItemList.size() - m_skippedProbable
UnderInvalidationCount - 1], | 672 m_newDisplayItemList[m_newDisplayItemList.size() - m_skippedProbable
UnderInvalidationCount - 1], |
576 &m_currentPaintArtifact.getDisplayItemList()[m_underInvalidationChec
kingBegin]); | 673 &m_currentPaintArtifact.getDisplayItemList()[m_underInvalidationChec
kingBegin]); |
577 NOTREACHED(); | 674 NOTREACHED(); |
578 } | 675 } |
579 | 676 |
| 677 // Discard the forced repainted display item and move the cached item into m
_newDisplayItemList. |
| 678 // This is to align with the non-under-invalidation-checking path to empty t
he original cached slot, |
| 679 // leaving only disappeared or invalidated display items in the old list aft
er painting. |
| 680 m_newDisplayItemList.removeLast(); |
| 681 m_newDisplayItemList.appendByMoving(*oldItem); |
| 682 |
580 ++m_underInvalidationCheckingBegin; | 683 ++m_underInvalidationCheckingBegin; |
581 } | 684 } |
582 | 685 |
583 #endif // DCHECK_IS_ON() | 686 #endif // DCHECK_IS_ON() |
584 | 687 |
585 String PaintController::displayItemListAsDebugString(const DisplayItemList& list
) const | 688 String PaintController::displayItemListAsDebugString(const DisplayItemList& list
) const |
586 { | 689 { |
587 StringBuilder stringBuilder; | 690 StringBuilder stringBuilder; |
588 size_t i = 0; | 691 size_t i = 0; |
589 for (auto it = list.begin(); it != list.end(); ++it, ++i) { | 692 for (auto it = list.begin(); it != list.end(); ++it, ++i) { |
590 const DisplayItem& displayItem = *it; | 693 const DisplayItem& displayItem = *it; |
591 if (i) | 694 if (i) |
592 stringBuilder.append(",\n"); | 695 stringBuilder.append(",\n"); |
593 stringBuilder.append(String::format("{index: %d, ", (int)i)); | 696 stringBuilder.append(String::format("{index: %d, ", (int)i)); |
594 #ifndef NDEBUG | 697 #ifndef NDEBUG |
595 displayItem.dumpPropertiesAsDebugString(stringBuilder); | 698 displayItem.dumpPropertiesAsDebugString(stringBuilder); |
596 #else | 699 #else |
597 stringBuilder.append(String::format("clientDebugName: %s", displayItem.c
lient().debugName().ascii().data())); | 700 stringBuilder.append(String::format("clientDebugName: %s", displayItem.c
lient().debugName().ascii().data())); |
598 #endif | 701 #endif |
599 if (displayItem.hasValidClient()) { | 702 if (displayItem.hasValidClient()) { |
600 stringBuilder.append(", cacheIsValid: "); | 703 do { |
601 stringBuilder.append(clientCacheIsValid(displayItem.client()) ? "tru
e" : "false"); | 704 #if CHECK_DISPLAY_ITEM_CLIENT_ALIVENESS |
| 705 if (!displayItem.client().isAlive()) { |
| 706 stringBuilder.append(", clientIsAlive: false"); |
| 707 break; |
| 708 } |
| 709 #endif |
| 710 stringBuilder.append(", cacheIsValid: "); |
| 711 stringBuilder.append(clientCacheIsValid(displayItem.client()) ?
"true" : "false"); |
| 712 } while (false); |
602 } | 713 } |
603 if (list.hasVisualRect(i)) { | 714 if (list.hasVisualRect(i)) { |
604 IntRect visualRect = list.visualRect(i); | 715 IntRect visualRect = list.visualRect(i); |
605 stringBuilder.append(String::format(", visualRect: [%d,%d %dx%d]", | 716 stringBuilder.append(String::format(", visualRect: [%d,%d %dx%d]", |
606 visualRect.x(), visualRect.y(), | 717 visualRect.x(), visualRect.y(), |
607 visualRect.width(), visualRect.height())); | 718 visualRect.width(), visualRect.height())); |
608 } | 719 } |
609 stringBuilder.append('}'); | 720 stringBuilder.append('}'); |
610 } | 721 } |
611 return stringBuilder.toString(); | 722 return stringBuilder.toString(); |
612 } | 723 } |
613 | 724 |
614 void PaintController::showDebugData() const | 725 void PaintController::showDebugData() const |
615 { | 726 { |
616 WTFLogAlways("current display item list: [%s]\n", displayItemListAsDebugStri
ng(m_currentPaintArtifact.getDisplayItemList()).utf8().data()); | 727 WTFLogAlways("current display item list: [%s]\n", displayItemListAsDebugStri
ng(m_currentPaintArtifact.getDisplayItemList()).utf8().data()); |
617 WTFLogAlways("new display item list: [%s]\n", displayItemListAsDebugString(m
_newDisplayItemList).utf8().data()); | 728 WTFLogAlways("new display item list: [%s]\n", displayItemListAsDebugString(m
_newDisplayItemList).utf8().data()); |
618 } | 729 } |
619 | 730 |
620 } // namespace blink | 731 } // namespace blink |
OLD | NEW |