OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2012 Google Inc. All rights reserved. | 2 * Copyright (C) 2012 Google Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
6 * are met: | 6 * are met: |
7 * | 7 * |
8 * 1. Redistributions of source code must retain the above copyright | 8 * 1. Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * 2. Redistributions in binary form must reproduce the above copyright | 10 * 2. Redistributions in binary form must reproduce the above copyright |
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
198 bridge->hibernate(); | 198 bridge->hibernate(); |
199 } else { | 199 } else { |
200 Canvas2DLayerBridge::Logger localLogger; | 200 Canvas2DLayerBridge::Logger localLogger; |
201 localLogger.reportHibernationEvent(Canvas2DLayerBridge::HibernationAbort
edDueToDestructionWhileHibernatePending); | 201 localLogger.reportHibernationEvent(Canvas2DLayerBridge::HibernationAbort
edDueToDestructionWhileHibernatePending); |
202 } | 202 } |
203 } | 203 } |
204 | 204 |
205 void Canvas2DLayerBridge::hibernate() | 205 void Canvas2DLayerBridge::hibernate() |
206 { | 206 { |
207 ASSERT(!isHibernating()); | 207 ASSERT(!isHibernating()); |
| 208 |
208 if (m_destructionInProgress) { | 209 if (m_destructionInProgress) { |
209 m_logger->reportHibernationEvent(HibernationAbortedDueToPendingDestructi
on); | 210 m_logger->reportHibernationEvent(HibernationAbortedDueToPendingDestructi
on); |
210 return; | 211 return; |
211 } | 212 } |
212 | 213 |
| 214 if (!m_surface) { |
| 215 m_logger->reportHibernationEvent(HibernationAbortedBecauseNoSurface); |
| 216 return; |
| 217 } |
| 218 |
213 if (!isHidden()) { | 219 if (!isHidden()) { |
214 m_logger->reportHibernationEvent(HibernationAbortedDueToVisibilityChange
); | 220 m_logger->reportHibernationEvent(HibernationAbortedDueToVisibilityChange
); |
215 return; | 221 return; |
216 } | 222 } |
217 | 223 |
218 if (!checkSurfaceValid()) { | 224 if (!checkSurfaceValid()) { |
219 m_logger->reportHibernationEvent(HibernationAbortedDueGpuContextLoss); | 225 m_logger->reportHibernationEvent(HibernationAbortedDueGpuContextLoss); |
220 return; | 226 return; |
221 } | 227 } |
222 | 228 |
223 if (!isAccelerated()) { | 229 if (!isAccelerated()) { |
224 m_logger->reportHibernationEvent(HibernationAbortedDueToSwitchToUnaccele
ratedRendering); | 230 m_logger->reportHibernationEvent(HibernationAbortedDueToSwitchToUnaccele
ratedRendering); |
225 return; | 231 return; |
226 } | 232 } |
227 | 233 |
228 TRACE_EVENT0("cc", "Canvas2DLayerBridge::hibernate"); | 234 TRACE_EVENT0("cc", "Canvas2DLayerBridge::hibernate"); |
229 RefPtr<SkSurface> tempHibernationSurface = adoptRef(SkSurface::NewRasterN32P
remul(m_size.width(), m_size.height())); | 235 RefPtr<SkSurface> tempHibernationSurface = adoptRef(SkSurface::NewRasterN32P
remul(m_size.width(), m_size.height())); |
230 if (tempHibernationSurface) { | 236 if (!tempHibernationSurface) { |
231 // No HibernationEvent reported on success. This is on purppose to avoid | |
232 // non-complementary stats. Each HibernationScheduled event is paired wi
th | |
233 // exactly one failure or exit event. | |
234 flushRecordingOnly(); | |
235 SkPaint copyPaint; | |
236 copyPaint.setXfermodeMode(SkXfermode::kSrc_Mode); | |
237 m_surface->draw(tempHibernationSurface->getCanvas(), 0, 0, ©Paint);
// GPU readback | |
238 m_hibernationImage = adoptRef(tempHibernationSurface->newImageSnapshot()
); | |
239 m_surface.clear(); // destroy the GPU-backed buffer | |
240 m_layer->clearTexture(); | |
241 m_logger->didStartHibernating(); | |
242 } else { | |
243 m_logger->reportHibernationEvent(HibernationAbortedDueToAllocationFailur
e); | 237 m_logger->reportHibernationEvent(HibernationAbortedDueToAllocationFailur
e); |
| 238 return; |
| 239 } |
| 240 // No HibernationEvent reported on success. This is on purppose to avoid |
| 241 // non-complementary stats. Each HibernationScheduled event is paired with |
| 242 // exactly one failure or exit event. |
| 243 flushRecordingOnly(); |
| 244 // The following checks that the flush succeeded, which should always be the |
| 245 // case because flushRecordingOnly should only fail it it fails to allocate |
| 246 // a surface, and we have an early exit at the top of this function for when |
| 247 // 'this' does not already have a surface. |
| 248 ASSERT(!m_haveRecordedDrawCommands); |
| 249 SkPaint copyPaint; |
| 250 copyPaint.setXfermodeMode(SkXfermode::kSrc_Mode); |
| 251 m_surface->draw(tempHibernationSurface->getCanvas(), 0, 0, ©Paint); // G
PU readback |
| 252 m_hibernationImage = adoptRef(tempHibernationSurface->newImageSnapshot()); |
| 253 m_surface.clear(); // destroy the GPU-backed buffer |
| 254 m_layer->clearTexture(); |
| 255 m_logger->didStartHibernating(); |
| 256 |
| 257 } |
| 258 |
| 259 void Canvas2DLayerBridge::reportSurfaceCreationFailure() |
| 260 { |
| 261 if (!m_surfaceCreationFailedAtLeastOnce) { |
| 262 // Only count the failure once per instance so that the histogram may |
| 263 // reflect the proportion of Canvas2DLayerBridge instances with surface |
| 264 // allocation failures. |
| 265 CanvasMetrics::countCanvasContextUsage(CanvasMetrics::GPUAccelerated2DCa
nvasSurfaceCreationFailed); |
| 266 m_surfaceCreationFailedAtLeastOnce = true; |
244 } | 267 } |
245 } | 268 } |
246 | 269 |
247 SkSurface* Canvas2DLayerBridge::getOrCreateSurface(AccelerationHint hint) | 270 SkSurface* Canvas2DLayerBridge::getOrCreateSurface(AccelerationHint hint) |
248 { | 271 { |
249 if (m_surface) | 272 if (m_surface) |
250 return m_surface.get(); | 273 return m_surface.get(); |
251 | 274 |
252 if (m_layer && !isHibernating() && hint == PreferAcceleration) { | 275 if (m_layer && !isHibernating() && hint == PreferAcceleration) { |
253 return nullptr; // re-creation will happen through restore() | 276 return nullptr; // re-creation will happen through restore() |
254 } | 277 } |
255 | 278 |
256 bool wantAcceleration = shouldAccelerate(hint); | 279 bool wantAcceleration = shouldAccelerate(hint); |
257 bool surfaceIsAccelerated; | 280 bool surfaceIsAccelerated; |
258 | 281 |
259 if (isHidden() && wantAcceleration) { | 282 if (isHidden() && wantAcceleration) { |
260 wantAcceleration = false; | 283 wantAcceleration = false; |
261 m_softwareRenderingWhileHidden = true; | 284 m_softwareRenderingWhileHidden = true; |
262 } | 285 } |
263 | 286 |
264 m_surface = createSkSurface(wantAcceleration ? m_contextProvider->grContext(
) : nullptr, m_size, m_msaaSampleCount, m_opacityMode, &surfaceIsAccelerated); | 287 m_surface = createSkSurface(wantAcceleration ? m_contextProvider->grContext(
) : nullptr, m_size, m_msaaSampleCount, m_opacityMode, &surfaceIsAccelerated); |
265 | 288 |
| 289 if (!m_surface) |
| 290 reportSurfaceCreationFailure(); |
| 291 |
266 if (m_surface && surfaceIsAccelerated && !m_layer) { | 292 if (m_surface && surfaceIsAccelerated && !m_layer) { |
267 m_layer = adoptPtr(Platform::current()->compositorSupport()->createExter
nalTextureLayer(this)); | 293 m_layer = adoptPtr(Platform::current()->compositorSupport()->createExter
nalTextureLayer(this)); |
268 m_layer->setOpaque(m_opacityMode == Opaque); | 294 m_layer->setOpaque(m_opacityMode == Opaque); |
269 m_layer->setBlendBackgroundColor(m_opacityMode != Opaque); | 295 m_layer->setBlendBackgroundColor(m_opacityMode != Opaque); |
270 GraphicsLayer::registerContentsLayer(m_layer->layer()); | 296 GraphicsLayer::registerContentsLayer(m_layer->layer()); |
271 m_layer->setNearestNeighbor(m_filterQuality == kNone_SkFilterQuality); | 297 m_layer->setNearestNeighbor(m_filterQuality == kNone_SkFilterQuality); |
272 } | 298 } |
273 | 299 |
274 if (m_surface && isHibernating()) { | 300 if (m_surface && isHibernating()) { |
275 if (surfaceIsAccelerated) { | 301 if (surfaceIsAccelerated) { |
276 m_logger->reportHibernationEvent(HibernationEndedNormally); | 302 m_logger->reportHibernationEvent(HibernationEndedNormally); |
277 } else { | 303 } else { |
278 if (isHidden()) | 304 if (isHidden()) |
279 m_logger->reportHibernationEvent(HibernationEndedWithSwitchToBac
kgroundRendering); | 305 m_logger->reportHibernationEvent(HibernationEndedWithSwitchToBac
kgroundRendering); |
280 else | 306 else |
281 m_logger->reportHibernationEvent(HibernationEndedWithFallbackToS
W); | 307 m_logger->reportHibernationEvent(HibernationEndedWithFallbackToS
W); |
282 } | 308 } |
283 | 309 |
284 SkPaint copyPaint; | 310 SkPaint copyPaint; |
285 copyPaint.setXfermodeMode(SkXfermode::kSrc_Mode); | 311 copyPaint.setXfermodeMode(SkXfermode::kSrc_Mode); |
286 m_surface->getCanvas()->drawImage(m_hibernationImage.get(), 0, 0, ©P
aint); | 312 m_surface->getCanvas()->drawImage(m_hibernationImage.get(), 0, 0, ©P
aint); |
287 m_hibernationImage.clear(); | 313 m_hibernationImage.clear(); |
288 | 314 |
289 if (m_imageBuffer) | 315 if (m_imageBuffer) |
290 m_imageBuffer->updateGPUMemoryUsage(); | 316 m_imageBuffer->updateGPUMemoryUsage(); |
291 | 317 |
292 if (m_imageBuffer && !m_isDeferralEnabled) | 318 if (m_imageBuffer && !m_isDeferralEnabled) |
293 m_imageBuffer->resetCanvas(m_surface->getCanvas()); | 319 m_imageBuffer->resetCanvas(m_surface->getCanvas()); |
294 } | 320 } |
| 321 |
295 return m_surface.get(); | 322 return m_surface.get(); |
296 } | 323 } |
297 | 324 |
298 SkCanvas* Canvas2DLayerBridge::canvas() | 325 SkCanvas* Canvas2DLayerBridge::canvas() |
299 { | 326 { |
300 if (!m_isDeferralEnabled) { | 327 if (!m_isDeferralEnabled) { |
301 SkSurface* s = getOrCreateSurface(); | 328 SkSurface* s = getOrCreateSurface(); |
302 return s ? s->getCanvas() : nullptr; | 329 return s ? s->getCanvas() : nullptr; |
303 } | 330 } |
304 return m_recorder->getRecordingCanvas(); | 331 return m_recorder->getRecordingCanvas(); |
305 } | 332 } |
306 | 333 |
307 void Canvas2DLayerBridge::disableDeferral() | 334 void Canvas2DLayerBridge::disableDeferral() |
308 { | 335 { |
309 // Disabling deferral is permanent: once triggered by disableDeferral() | 336 // Disabling deferral is permanent: once triggered by disableDeferral() |
310 // we stay in immediate mode indefinitely. This is a performance heuristic | 337 // we stay in immediate mode indefinitely. This is a performance heuristic |
311 // that significantly helps a number of use cases. The rationale is that if | 338 // that significantly helps a number of use cases. The rationale is that if |
312 // immediate rendering was needed once, it is likely to be needed at least | 339 // immediate rendering was needed once, it is likely to be needed at least |
313 // once per frame, which eliminates the possibility for inter-frame | 340 // once per frame, which eliminates the possibility for inter-frame |
314 // overdraw optimization. Furthermore, in cases where immediate mode is | 341 // overdraw optimization. Furthermore, in cases where immediate mode is |
315 // required multiple times per frame, the repeated flushing of deferred | 342 // required multiple times per frame, the repeated flushing of deferred |
316 // commands would cause significant overhead, so it is better to just stop | 343 // commands would cause significant overhead, so it is better to just stop |
317 // trying to defer altogether. | 344 // trying to defer altogether. |
318 if (!m_isDeferralEnabled) | 345 if (!m_isDeferralEnabled) |
319 return; | 346 return; |
320 | 347 |
| 348 CanvasMetrics::countCanvasContextUsage(CanvasMetrics::GPUAccelerated2DCanvas
DeferralDisabled); |
| 349 flushRecordingOnly(); |
| 350 // Because we will be discarding the recorder, if the flush failed |
| 351 // content will be lost -> force m_haveRecordedDrawCommands to false |
| 352 m_haveRecordedDrawCommands = false; |
| 353 |
321 m_isDeferralEnabled = false; | 354 m_isDeferralEnabled = false; |
322 flushRecordingOnly(); | |
323 m_recorder.clear(); | 355 m_recorder.clear(); |
324 // install the current matrix/clip stack onto the immediate canvas | 356 // install the current matrix/clip stack onto the immediate canvas |
325 SkSurface* surface = getOrCreateSurface(); | 357 SkSurface* surface = getOrCreateSurface(); |
326 if (m_imageBuffer && surface) | 358 if (m_imageBuffer && surface) |
327 m_imageBuffer->resetCanvas(surface->getCanvas()); | 359 m_imageBuffer->resetCanvas(surface->getCanvas()); |
328 } | 360 } |
329 | 361 |
330 void Canvas2DLayerBridge::setImageBuffer(ImageBuffer* imageBuffer) | 362 void Canvas2DLayerBridge::setImageBuffer(ImageBuffer* imageBuffer) |
331 { | 363 { |
332 m_imageBuffer = imageBuffer; | 364 m_imageBuffer = imageBuffer; |
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
515 WebGraphicsContext3D* sharedContext = 0; | 547 WebGraphicsContext3D* sharedContext = 0; |
516 m_layer->clearTexture(); | 548 m_layer->clearTexture(); |
517 m_contextProvider = adoptPtr(Platform::current()->createSharedOffscreenGraph
icsContext3DProvider()); | 549 m_contextProvider = adoptPtr(Platform::current()->createSharedOffscreenGraph
icsContext3DProvider()); |
518 if (m_contextProvider) | 550 if (m_contextProvider) |
519 sharedContext = m_contextProvider->context3d(); | 551 sharedContext = m_contextProvider->context3d(); |
520 | 552 |
521 if (sharedContext && !sharedContext->isContextLost()) { | 553 if (sharedContext && !sharedContext->isContextLost()) { |
522 GrContext* grCtx = m_contextProvider->grContext(); | 554 GrContext* grCtx = m_contextProvider->grContext(); |
523 bool surfaceIsAccelerated; | 555 bool surfaceIsAccelerated; |
524 RefPtr<SkSurface> surface(createSkSurface(grCtx, m_size, m_msaaSampleCou
nt, m_opacityMode, &surfaceIsAccelerated)); | 556 RefPtr<SkSurface> surface(createSkSurface(grCtx, m_size, m_msaaSampleCou
nt, m_opacityMode, &surfaceIsAccelerated)); |
| 557 |
| 558 if (!m_surface) |
| 559 reportSurfaceCreationFailure(); |
| 560 |
525 // Current paradigm does support switching from accelerated to non-accel
erated, which would be tricky | 561 // Current paradigm does support switching from accelerated to non-accel
erated, which would be tricky |
526 // due to changes to the layer tree, which can only happen at specific t
imes during the document lifecycle. | 562 // due to changes to the layer tree, which can only happen at specific t
imes during the document lifecycle. |
527 // Therefore, we can only accept the restored surface if it is accelerat
ed. | 563 // Therefore, we can only accept the restored surface if it is accelerat
ed. |
528 if (surface && surfaceIsAccelerated) { | 564 if (surface && surfaceIsAccelerated) { |
529 m_surface = surface.release(); | 565 m_surface = surface.release(); |
530 // FIXME: draw sad canvas picture into new buffer crbug.com/243842 | 566 // FIXME: draw sad canvas picture into new buffer crbug.com/243842 |
531 } | 567 } |
532 } | 568 } |
533 if (m_imageBuffer) | 569 if (m_imageBuffer) |
534 m_imageBuffer->updateGPUMemoryUsage(); | 570 m_imageBuffer->updateGPUMemoryUsage(); |
(...skipping 248 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
783 m_image = other.m_image; | 819 m_image = other.m_image; |
784 m_parentLayerBridge = other.m_parentLayerBridge; | 820 m_parentLayerBridge = other.m_parentLayerBridge; |
785 } | 821 } |
786 | 822 |
787 void Canvas2DLayerBridge::Logger::reportHibernationEvent(HibernationEvent event) | 823 void Canvas2DLayerBridge::Logger::reportHibernationEvent(HibernationEvent event) |
788 { | 824 { |
789 blink::Platform::current()->histogramEnumeration("Canvas.HibernationEvents",
event, HibernationEventCount); | 825 blink::Platform::current()->histogramEnumeration("Canvas.HibernationEvents",
event, HibernationEventCount); |
790 } | 826 } |
791 | 827 |
792 } // namespace blink | 828 } // namespace blink |
OLD | NEW |