Index: Source/platform/graphics/Canvas2DLayerBridge.cpp |
diff --git a/Source/platform/graphics/Canvas2DLayerBridge.cpp b/Source/platform/graphics/Canvas2DLayerBridge.cpp |
index 6208b58592df5dc25d1887943aa47b58509af8ac..f33300a52a2f25773036320fdef0ea3087c29dd9 100644 |
--- a/Source/platform/graphics/Canvas2DLayerBridge.cpp |
+++ b/Source/platform/graphics/Canvas2DLayerBridge.cpp |
@@ -98,6 +98,7 @@ Canvas2DLayerBridge::Canvas2DLayerBridge(PassOwnPtr<WebGraphicsContext3DProvider |
, m_rateLimitingEnabled(false) |
, m_filterQuality(kLow_SkFilterQuality) |
, m_isHidden(false) |
+ , m_isDeferralEnabled(true) |
, m_lastImageId(0) |
, m_lastFilter(GL_LINEAR) |
, m_opacityMode(opacityMode) |
@@ -132,6 +133,7 @@ Canvas2DLayerBridge::~Canvas2DLayerBridge() |
void Canvas2DLayerBridge::startRecording() |
{ |
+ ASSERT(m_isDeferralEnabled); |
m_recorder = adoptPtr(new SkPictureRecorder); |
m_recorder->beginRecording(m_size.width(), m_size.height(), nullptr); |
if (m_imageBuffer) { |
@@ -141,26 +143,36 @@ void Canvas2DLayerBridge::startRecording() |
SkCanvas* Canvas2DLayerBridge::canvas() |
{ |
+ if (!m_isDeferralEnabled) |
+ return m_surface->getCanvas(); |
return m_recorder->getRecordingCanvas(); |
} |
-SkCanvas* Canvas2DLayerBridge::immediateCanvas() |
+void Canvas2DLayerBridge::disableDeferral() |
{ |
- if (!m_surface) |
- return nullptr; |
- flushRecordingOnly(); |
+ // Disabling deferral is permanent: once triggered by disableDeferral() |
+ // we stay in immediate mode indefinitely. This is a performance heuristic |
+ // that significantly helps a number of use cases. The rationale is that if |
+ // immediate rendering was needed once, it is likely to be needed at least |
+ // once per frame, which eliminates the possibility for inter-frame |
+ // overdraw optimization. Furthermore, in cases where immediate mode is |
+ // required multiple times per frame, the repeated flushing of deferred |
+ // commands would cause significant overhead, so it is better to just stop |
+ // trying to defer altogether. |
+ if (!m_isDeferralEnabled) |
+ return; |
+ m_isDeferralEnabled = false; |
+ flushRecordingOnly(); |
+ m_recorder.clear(); |
// install the current matrix/clip stack onto the immediate canvas |
- m_surface->getCanvas()->restoreToCount(m_initialSurfaceSaveCount); |
m_imageBuffer->resetCanvas(m_surface->getCanvas()); |
- |
- return m_surface->getCanvas(); |
} |
void Canvas2DLayerBridge::setImageBuffer(ImageBuffer* imageBuffer) |
{ |
m_imageBuffer = imageBuffer; |
- if (m_imageBuffer) { |
+ if (m_imageBuffer && m_isDeferralEnabled) { |
m_imageBuffer->resetCanvas(m_recorder->getRecordingCanvas()); |
} |
} |
@@ -246,9 +258,9 @@ void Canvas2DLayerBridge::flushRecordingOnly() |
if (m_haveRecordedDrawCommands && m_surface) { |
TRACE_EVENT0("cc", "Canvas2DLayerBridge::flush"); |
RefPtr<SkPicture> picture = adoptRef(m_recorder->endRecording()); |
- m_surface->getCanvas()->restoreToCount(m_initialSurfaceSaveCount); // In case immediateCanvas() was used |
picture->playback(m_surface->getCanvas()); |
- startRecording(); |
+ if (m_isDeferralEnabled) |
+ startRecording(); |
m_haveRecordedDrawCommands = false; |
} |
} |
@@ -479,14 +491,14 @@ WebLayer* Canvas2DLayerBridge::layer() const |
void Canvas2DLayerBridge::didDraw() |
{ |
- m_haveRecordedDrawCommands = true; |
+ if (m_isDeferralEnabled) |
+ m_haveRecordedDrawCommands = true; |
} |
void Canvas2DLayerBridge::finalizeFrame(const FloatRect &dirtyRect) |
{ |
ASSERT(!m_destructionInProgress); |
m_layer->layer()->invalidateRect(enclosingIntRect(dirtyRect)); |
- |
m_framesPending++; |
if (m_framesPending > 1) { |
// Turn on the rate limiter if this layer tends to accumulate a |