Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(280)

Side by Side Diff: third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.cpp

Issue 1581403004: Fix crash in Canvas2DLayerBridge flushing + reliability metrics (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: test fix Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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, &copyPaint); // 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, &copyPaint); // 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, &copyP aint); 312 m_surface->getCanvas()->drawImage(m_hibernationImage.get(), 0, 0, &copyP 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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698