| 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 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 49 enum { | 49 enum { |
| 50 InvalidMailboxIndex = -1, | 50 InvalidMailboxIndex = -1, |
| 51 MaxCanvasAnimationBacklog = 2, // Make sure the the GPU is never more than t
wo animation frames behind. | 51 MaxCanvasAnimationBacklog = 2, // Make sure the the GPU is never more than t
wo animation frames behind. |
| 52 }; | 52 }; |
| 53 | 53 |
| 54 DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, canvas2DLayerBridgeInstance
Counter, ("Canvas2DLayerBridge")); | 54 DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, canvas2DLayerBridgeInstance
Counter, ("Canvas2DLayerBridge")); |
| 55 } | 55 } |
| 56 | 56 |
| 57 namespace blink { | 57 namespace blink { |
| 58 | 58 |
| 59 static PassRefPtr<SkSurface> createSkSurface(GrContext* gr, const IntSize& size,
int msaaSampleCount, OpacityMode opacityMode) | 59 static PassRefPtr<SkSurface> createSkSurface(GrContext* gr, const IntSize& size,
int msaaSampleCount, OpacityMode opacityMode, bool* surfaceIsAccelerated) |
| 60 { | 60 { |
| 61 if (!gr) | 61 if (gr) |
| 62 return nullptr; | 62 gr->resetContext(); |
| 63 gr->resetContext(); | 63 |
| 64 SkImageInfo info = SkImageInfo::MakeN32Premul(size.width(), size.height()); | 64 SkAlphaType alphaType = (Opaque == opacityMode) ? kOpaque_SkAlphaType : kPre
mul_SkAlphaType; |
| 65 SkImageInfo info = SkImageInfo::MakeN32(size.width(), size.height(), alphaTy
pe); |
| 65 SkSurfaceProps disableLCDProps(0, kUnknown_SkPixelGeometry); | 66 SkSurfaceProps disableLCDProps(0, kUnknown_SkPixelGeometry); |
| 66 RefPtr<SkSurface> surface = adoptRef(SkSurface::NewRenderTarget(gr, SkSurfac
e::kNo_Budgeted, info, msaaSampleCount, | 67 RefPtr<SkSurface> surface; |
| 67 Opaque == opacityMode ? 0 : &disableLCDProps)); | 68 |
| 69 if (gr) { |
| 70 *surfaceIsAccelerated = true; |
| 71 surface = adoptRef(SkSurface::NewRenderTarget(gr, SkSurface::kNo_Budgete
d, info, msaaSampleCount, Opaque == opacityMode ? 0 : &disableLCDProps)); |
| 72 } |
| 73 |
| 74 if (!surface) { |
| 75 *surfaceIsAccelerated = false; |
| 76 surface = adoptRef(SkSurface::NewRaster(info, Opaque == opacityMode ? 0
: &disableLCDProps)); |
| 77 } |
| 78 |
| 68 if (surface) { | 79 if (surface) { |
| 69 if (opacityMode == Opaque) { | 80 if (opacityMode == Opaque) { |
| 70 surface->getCanvas()->clear(SK_ColorBLACK); | 81 surface->getCanvas()->clear(SK_ColorBLACK); |
| 71 } else { | 82 } else { |
| 72 surface->getCanvas()->clear(SK_ColorTRANSPARENT); | 83 surface->getCanvas()->clear(SK_ColorTRANSPARENT); |
| 73 } | 84 } |
| 74 } | 85 } |
| 75 return surface; | 86 return surface; |
| 76 } | 87 } |
| 77 | 88 |
| 78 PassRefPtr<Canvas2DLayerBridge> Canvas2DLayerBridge::create(const IntSize& size,
OpacityMode opacityMode, int msaaSampleCount) | 89 PassRefPtr<Canvas2DLayerBridge> Canvas2DLayerBridge::create(const IntSize& size,
int msaaSampleCount, OpacityMode opacityMode, AccelerationMode accelerationMode
) |
| 79 { | 90 { |
| 80 TRACE_EVENT_INSTANT0("test_gpu", "Canvas2DLayerBridgeCreation", TRACE_EVENT_
SCOPE_GLOBAL); | 91 TRACE_EVENT_INSTANT0("test_gpu", "Canvas2DLayerBridgeCreation", TRACE_EVENT_
SCOPE_GLOBAL); |
| 81 OwnPtr<WebGraphicsContext3DProvider> contextProvider = adoptPtr(Platform::cu
rrent()->createSharedOffscreenGraphicsContext3DProvider()); | 92 OwnPtr<WebGraphicsContext3DProvider> contextProvider = adoptPtr(Platform::cu
rrent()->createSharedOffscreenGraphicsContext3DProvider()); |
| 82 if (!contextProvider) | 93 if (!contextProvider) |
| 83 return nullptr; | 94 return nullptr; |
| 84 RefPtr<SkSurface> surface(createSkSurface(contextProvider->grContext(), size
, msaaSampleCount, opacityMode)); | |
| 85 if (!surface) | |
| 86 return nullptr; | |
| 87 RefPtr<Canvas2DLayerBridge> layerBridge; | 95 RefPtr<Canvas2DLayerBridge> layerBridge; |
| 88 layerBridge = adoptRef(new Canvas2DLayerBridge(contextProvider.release(), su
rface.release(), msaaSampleCount, opacityMode)); | 96 layerBridge = adoptRef(new Canvas2DLayerBridge(contextProvider.release(), si
ze, msaaSampleCount, opacityMode, accelerationMode)); |
| 89 return layerBridge.release(); | 97 return layerBridge.release(); |
| 90 } | 98 } |
| 91 | 99 |
| 92 Canvas2DLayerBridge::Canvas2DLayerBridge(PassOwnPtr<WebGraphicsContext3DProvider
> contextProvider, PassRefPtr<SkSurface> surface, int msaaSampleCount, OpacityMo
de opacityMode) | 100 Canvas2DLayerBridge::Canvas2DLayerBridge(PassOwnPtr<WebGraphicsContext3DProvider
> contextProvider, const IntSize& size, int msaaSampleCount, OpacityMode opacity
Mode, AccelerationMode accelerationMode) |
| 93 : m_surface(surface) | 101 : m_contextProvider(contextProvider) |
| 94 , m_contextProvider(contextProvider) | |
| 95 , m_imageBuffer(0) | 102 , m_imageBuffer(0) |
| 96 , m_msaaSampleCount(msaaSampleCount) | 103 , m_msaaSampleCount(msaaSampleCount) |
| 97 , m_bytesAllocated(0) | 104 , m_bytesAllocated(0) |
| 98 , m_haveRecordedDrawCommands(false) | 105 , m_haveRecordedDrawCommands(false) |
| 99 , m_destructionInProgress(false) | 106 , m_destructionInProgress(false) |
| 100 , m_filterQuality(kLow_SkFilterQuality) | 107 , m_filterQuality(kLow_SkFilterQuality) |
| 101 , m_isHidden(false) | 108 , m_isHidden(false) |
| 102 , m_isDeferralEnabled(true) | 109 , m_isDeferralEnabled(true) |
| 103 , m_isRegisteredTaskObserver(false) | 110 , m_isRegisteredTaskObserver(false) |
| 104 , m_renderingTaskCompletedForCurrentFrame(false) | 111 , m_renderingTaskCompletedForCurrentFrame(false) |
| 105 , m_lastImageId(0) | 112 , m_lastImageId(0) |
| 106 , m_lastFilter(GL_LINEAR) | 113 , m_lastFilter(GL_LINEAR) |
| 114 , m_accelerationMode(accelerationMode) |
| 107 , m_opacityMode(opacityMode) | 115 , m_opacityMode(opacityMode) |
| 108 , m_size(m_surface->width(), m_surface->height()) | 116 , m_size(size) |
| 109 { | 117 { |
| 110 ASSERT(m_surface); | |
| 111 ASSERT(m_contextProvider); | 118 ASSERT(m_contextProvider); |
| 112 m_initialSurfaceSaveCount = m_surface->getCanvas()->getSaveCount(); | |
| 113 // Used by browser tests to detect the use of a Canvas2DLayerBridge. | 119 // Used by browser tests to detect the use of a Canvas2DLayerBridge. |
| 114 TRACE_EVENT_INSTANT0("test_gpu", "Canvas2DLayerBridgeCreation", TRACE_EVENT_
SCOPE_GLOBAL); | 120 TRACE_EVENT_INSTANT0("test_gpu", "Canvas2DLayerBridgeCreation", TRACE_EVENT_
SCOPE_GLOBAL); |
| 115 m_layer = adoptPtr(Platform::current()->compositorSupport()->createExternalT
extureLayer(this)); | |
| 116 m_layer->setOpaque(opacityMode == Opaque); | |
| 117 m_layer->setBlendBackgroundColor(opacityMode != Opaque); | |
| 118 GraphicsLayer::registerContentsLayer(m_layer->layer()); | |
| 119 m_layer->setNearestNeighbor(m_filterQuality == kNone_SkFilterQuality); | |
| 120 startRecording(); | 121 startRecording(); |
| 121 #ifndef NDEBUG | 122 #ifndef NDEBUG |
| 122 canvas2DLayerBridgeInstanceCounter.increment(); | 123 canvas2DLayerBridgeInstanceCounter.increment(); |
| 123 #endif | 124 #endif |
| 124 } | 125 } |
| 125 | 126 |
| 126 Canvas2DLayerBridge::~Canvas2DLayerBridge() | 127 Canvas2DLayerBridge::~Canvas2DLayerBridge() |
| 127 { | 128 { |
| 128 ASSERT(m_destructionInProgress); | 129 ASSERT(m_destructionInProgress); |
| 129 m_layer.clear(); | 130 m_layer.clear(); |
| 130 ASSERT(m_mailboxes.size() == 0); | 131 ASSERT(m_mailboxes.size() == 0); |
| 131 #ifndef NDEBUG | 132 #ifndef NDEBUG |
| 132 canvas2DLayerBridgeInstanceCounter.decrement(); | 133 canvas2DLayerBridgeInstanceCounter.decrement(); |
| 133 #endif | 134 #endif |
| 134 } | 135 } |
| 135 | 136 |
| 136 void Canvas2DLayerBridge::startRecording() | 137 void Canvas2DLayerBridge::startRecording() |
| 137 { | 138 { |
| 138 ASSERT(m_isDeferralEnabled); | 139 ASSERT(m_isDeferralEnabled); |
| 139 m_recorder = adoptPtr(new SkPictureRecorder); | 140 m_recorder = adoptPtr(new SkPictureRecorder); |
| 140 m_recorder->beginRecording(m_size.width(), m_size.height(), nullptr); | 141 m_recorder->beginRecording(m_size.width(), m_size.height(), nullptr); |
| 141 if (m_imageBuffer) { | 142 if (m_imageBuffer) { |
| 142 m_imageBuffer->resetCanvas(m_recorder->getRecordingCanvas()); | 143 m_imageBuffer->resetCanvas(m_recorder->getRecordingCanvas()); |
| 143 } | 144 } |
| 144 m_recordingPixelCount = 0; | 145 m_recordingPixelCount = 0; |
| 145 } | 146 } |
| 146 | 147 |
| 148 bool Canvas2DLayerBridge::shouldAccelerate(AccelerationHint hint) const |
| 149 { |
| 150 bool accelerate; |
| 151 if (m_accelerationMode == ForceAccelerationForTesting) |
| 152 accelerate = true; |
| 153 else if (m_accelerationMode == DisableAcceleration) |
| 154 accelerate = false; |
| 155 else |
| 156 accelerate = hint == PreferAcceleration; |
| 157 |
| 158 if (accelerate && (!m_contextProvider || m_contextProvider->context3d()->isC
ontextLost())) |
| 159 accelerate = false; |
| 160 return accelerate; |
| 161 } |
| 162 |
| 163 bool Canvas2DLayerBridge::isAccelerated() const |
| 164 { |
| 165 if (m_layer) // We don't check m_surface, so this returns true if context wa
s lost (m_surface is null) with restoration pending. |
| 166 return true; |
| 167 if (m_surface) // && !m_layer is implied |
| 168 return false; |
| 169 |
| 170 // Whether or not to accelerate is not yet resolved, determine whether immed
iate presentation |
| 171 // of the canvas would result in the canvas being accelerated. Presentation
is assumed to be |
| 172 // a 'PreferAcceleration' operation. |
| 173 return shouldAccelerate(PreferAcceleration); |
| 174 } |
| 175 |
| 176 SkSurface* Canvas2DLayerBridge::getOrCreateSurface(AccelerationHint hint) |
| 177 { |
| 178 if (!m_surface) { |
| 179 if (m_layer) |
| 180 return nullptr; // recreation will happen through restore() |
| 181 |
| 182 bool wantAccelerated = shouldAccelerate(hint); |
| 183 bool surfaceIsAccelerated; |
| 184 |
| 185 m_surface = createSkSurface(wantAccelerated ? m_contextProvider->grConte
xt() : nullptr, m_size, m_msaaSampleCount, m_opacityMode, &surfaceIsAccelerated)
; |
| 186 |
| 187 if (m_surface && surfaceIsAccelerated && !m_layer) { |
| 188 m_layer = adoptPtr(Platform::current()->compositorSupport()->createE
xternalTextureLayer(this)); |
| 189 m_layer->setOpaque(m_opacityMode == Opaque); |
| 190 m_layer->setBlendBackgroundColor(m_opacityMode != Opaque); |
| 191 GraphicsLayer::registerContentsLayer(m_layer->layer()); |
| 192 m_layer->setNearestNeighbor(m_filterQuality == kNone_SkFilterQuality
); |
| 193 } |
| 194 } |
| 195 return m_surface.get(); |
| 196 } |
| 197 |
| 147 SkCanvas* Canvas2DLayerBridge::canvas() | 198 SkCanvas* Canvas2DLayerBridge::canvas() |
| 148 { | 199 { |
| 149 if (!m_isDeferralEnabled) | 200 if (!m_isDeferralEnabled) { |
| 150 return m_surface->getCanvas(); | 201 SkSurface* s = getOrCreateSurface(); |
| 202 return s ? s->getCanvas() : nullptr; |
| 203 } |
| 151 return m_recorder->getRecordingCanvas(); | 204 return m_recorder->getRecordingCanvas(); |
| 152 } | 205 } |
| 153 | 206 |
| 154 void Canvas2DLayerBridge::disableDeferral() | 207 void Canvas2DLayerBridge::disableDeferral() |
| 155 { | 208 { |
| 156 // Disabling deferral is permanent: once triggered by disableDeferral() | 209 // Disabling deferral is permanent: once triggered by disableDeferral() |
| 157 // we stay in immediate mode indefinitely. This is a performance heuristic | 210 // we stay in immediate mode indefinitely. This is a performance heuristic |
| 158 // that significantly helps a number of use cases. The rationale is that if | 211 // that significantly helps a number of use cases. The rationale is that if |
| 159 // immediate rendering was needed once, it is likely to be needed at least | 212 // immediate rendering was needed once, it is likely to be needed at least |
| 160 // once per frame, which eliminates the possibility for inter-frame | 213 // once per frame, which eliminates the possibility for inter-frame |
| 161 // overdraw optimization. Furthermore, in cases where immediate mode is | 214 // overdraw optimization. Furthermore, in cases where immediate mode is |
| 162 // required multiple times per frame, the repeated flushing of deferred | 215 // required multiple times per frame, the repeated flushing of deferred |
| 163 // commands would cause significant overhead, so it is better to just stop | 216 // commands would cause significant overhead, so it is better to just stop |
| 164 // trying to defer altogether. | 217 // trying to defer altogether. |
| 165 if (!m_isDeferralEnabled) | 218 if (!m_isDeferralEnabled) |
| 166 return; | 219 return; |
| 167 | 220 |
| 168 m_isDeferralEnabled = false; | 221 m_isDeferralEnabled = false; |
| 169 flushRecordingOnly(); | 222 flushRecordingOnly(); |
| 170 m_recorder.clear(); | 223 m_recorder.clear(); |
| 171 // install the current matrix/clip stack onto the immediate canvas | 224 // install the current matrix/clip stack onto the immediate canvas |
| 172 m_imageBuffer->resetCanvas(m_surface->getCanvas()); | 225 m_imageBuffer->resetCanvas(getOrCreateSurface()->getCanvas()); |
| 173 } | 226 } |
| 174 | 227 |
| 175 void Canvas2DLayerBridge::setImageBuffer(ImageBuffer* imageBuffer) | 228 void Canvas2DLayerBridge::setImageBuffer(ImageBuffer* imageBuffer) |
| 176 { | 229 { |
| 177 m_imageBuffer = imageBuffer; | 230 m_imageBuffer = imageBuffer; |
| 178 if (m_imageBuffer && m_isDeferralEnabled) { | 231 if (m_imageBuffer && m_isDeferralEnabled) { |
| 179 m_imageBuffer->resetCanvas(m_recorder->getRecordingCanvas()); | 232 m_imageBuffer->resetCanvas(m_recorder->getRecordingCanvas()); |
| 180 } | 233 } |
| 181 } | 234 } |
| 182 | 235 |
| 183 void Canvas2DLayerBridge::beginDestruction() | 236 void Canvas2DLayerBridge::beginDestruction() |
| 184 { | 237 { |
| 185 ASSERT(!m_destructionInProgress); | 238 ASSERT(!m_destructionInProgress); |
| 186 m_recorder.clear(); | 239 m_recorder.clear(); |
| 187 m_imageBuffer = nullptr; | 240 m_imageBuffer = nullptr; |
| 188 m_destructionInProgress = true; | 241 m_destructionInProgress = true; |
| 189 setIsHidden(true); | 242 setIsHidden(true); |
| 190 GraphicsLayer::unregisterContentsLayer(m_layer->layer()); | |
| 191 m_surface.clear(); | 243 m_surface.clear(); |
| 192 m_layer->clearTexture(); | 244 |
| 193 // Orphaning the layer is required to trigger the recration of a new layer | |
| 194 // in the case where destruction is caused by a canvas resize. Test: | |
| 195 // virtual/gpu/fast/canvas/canvas-resize-after-paint-without-layout.html | |
| 196 m_layer->layer()->removeFromParent(); | |
| 197 // To anyone who ever hits this assert: Please update crbug.com/344666 | |
| 198 // with repro steps. | |
| 199 unregisterTaskObserver(); | 245 unregisterTaskObserver(); |
| 246 |
| 247 if (m_layer) { |
| 248 GraphicsLayer::unregisterContentsLayer(m_layer->layer()); |
| 249 m_layer->clearTexture(); |
| 250 // Orphaning the layer is required to trigger the recration of a new lay
er |
| 251 // in the case where destruction is caused by a canvas resize. Test: |
| 252 // virtual/gpu/fast/canvas/canvas-resize-after-paint-without-layout.html |
| 253 m_layer->layer()->removeFromParent(); |
| 254 } |
| 200 ASSERT(!m_bytesAllocated); | 255 ASSERT(!m_bytesAllocated); |
| 201 } | 256 } |
| 202 | 257 |
| 203 void Canvas2DLayerBridge::unregisterTaskObserver() | 258 void Canvas2DLayerBridge::unregisterTaskObserver() |
| 204 { | 259 { |
| 205 if (m_isRegisteredTaskObserver) { | 260 if (m_isRegisteredTaskObserver) { |
| 206 Platform::current()->currentThread()->removeTaskObserver(this); | 261 Platform::current()->currentThread()->removeTaskObserver(this); |
| 207 m_isRegisteredTaskObserver = false; | 262 m_isRegisteredTaskObserver = false; |
| 208 } | 263 } |
| 209 } | 264 } |
| 210 | 265 |
| 211 void Canvas2DLayerBridge::setFilterQuality(SkFilterQuality filterQuality) | 266 void Canvas2DLayerBridge::setFilterQuality(SkFilterQuality filterQuality) |
| 212 { | 267 { |
| 213 ASSERT(!m_destructionInProgress); | 268 ASSERT(!m_destructionInProgress); |
| 214 m_filterQuality = filterQuality; | 269 m_filterQuality = filterQuality; |
| 215 m_layer->setNearestNeighbor(m_filterQuality == kNone_SkFilterQuality); | 270 if (m_layer) |
| 271 m_layer->setNearestNeighbor(m_filterQuality == kNone_SkFilterQuality); |
| 216 } | 272 } |
| 217 | 273 |
| 218 void Canvas2DLayerBridge::setIsHidden(bool hidden) | 274 void Canvas2DLayerBridge::setIsHidden(bool hidden) |
| 219 { | 275 { |
| 220 bool newHiddenValue = hidden || m_destructionInProgress; | 276 bool newHiddenValue = hidden || m_destructionInProgress; |
| 221 if (m_isHidden == newHiddenValue) | 277 if (m_isHidden == newHiddenValue) |
| 222 return; | 278 return; |
| 223 | 279 |
| 224 m_isHidden = newHiddenValue; | 280 m_isHidden = newHiddenValue; |
| 225 if (isHidden() && !m_destructionInProgress) | 281 if (isHidden() && !m_destructionInProgress) |
| 226 flush(); | 282 flush(); |
| 227 } | 283 } |
| 228 | 284 |
| 229 bool Canvas2DLayerBridge::writePixels(const SkImageInfo& origInfo, const void* p
ixels, size_t rowBytes, int x, int y) | 285 bool Canvas2DLayerBridge::writePixels(const SkImageInfo& origInfo, const void* p
ixels, size_t rowBytes, int x, int y) |
| 230 { | 286 { |
| 231 if (!m_surface) | 287 if (!getOrCreateSurface()) |
| 232 return false; | 288 return false; |
| 233 if (x <= 0 && y <= 0 && x + origInfo.width() >= m_size.width() && y + origIn
fo.height() >= m_size.height()) { | 289 if (x <= 0 && y <= 0 && x + origInfo.width() >= m_size.width() && y + origIn
fo.height() >= m_size.height()) { |
| 234 skipQueuedDrawCommands(); | 290 skipQueuedDrawCommands(); |
| 235 } else { | 291 } else { |
| 236 flush(); | 292 flush(); |
| 237 } | 293 } |
| 238 ASSERT(!m_haveRecordedDrawCommands); | 294 ASSERT(!m_haveRecordedDrawCommands); |
| 239 // call write pixels on the surface, not the recording canvas. | 295 // call write pixels on the surface, not the recording canvas. |
| 240 // No need to call beginDirectSurfaceAccessModeIfNeeded() because writePixel
s | 296 // No need to call beginDirectSurfaceAccessModeIfNeeded() because writePixel
s |
| 241 // ignores the matrix and clip state. | 297 // ignores the matrix and clip state. |
| 242 return m_surface->getCanvas()->writePixels(origInfo, pixels, rowBytes, x, y)
; | 298 return getOrCreateSurface()->getCanvas()->writePixels(origInfo, pixels, rowB
ytes, x, y); |
| 243 } | 299 } |
| 244 | 300 |
| 245 void Canvas2DLayerBridge::skipQueuedDrawCommands() | 301 void Canvas2DLayerBridge::skipQueuedDrawCommands() |
| 246 { | 302 { |
| 247 if (m_haveRecordedDrawCommands) { | 303 if (m_haveRecordedDrawCommands) { |
| 248 adoptRef(m_recorder->endRecording()); | 304 adoptRef(m_recorder->endRecording()); |
| 249 startRecording(); | 305 startRecording(); |
| 250 m_haveRecordedDrawCommands = false; | 306 m_haveRecordedDrawCommands = false; |
| 251 } | 307 } |
| 252 | 308 |
| 253 if (m_isDeferralEnabled) { | 309 if (m_isDeferralEnabled) { |
| 254 unregisterTaskObserver(); | 310 unregisterTaskObserver(); |
| 255 if (m_rateLimiter) | 311 if (m_rateLimiter) |
| 256 m_rateLimiter->reset(); | 312 m_rateLimiter->reset(); |
| 257 } | 313 } |
| 258 } | 314 } |
| 259 | 315 |
| 260 void Canvas2DLayerBridge::flushRecordingOnly() | 316 void Canvas2DLayerBridge::flushRecordingOnly() |
| 261 { | 317 { |
| 262 ASSERT(!m_destructionInProgress); | 318 ASSERT(!m_destructionInProgress); |
| 263 if (m_haveRecordedDrawCommands && m_surface) { | 319 |
| 320 if (m_haveRecordedDrawCommands && getOrCreateSurface()) { |
| 321 TRACE_EVENT0("cc", "Canvas2DLayerBridge::flushRecordingOnly"); |
| 264 RefPtr<SkPicture> picture = adoptRef(m_recorder->endRecording()); | 322 RefPtr<SkPicture> picture = adoptRef(m_recorder->endRecording()); |
| 265 picture->playback(m_surface->getCanvas()); | 323 picture->playback(getOrCreateSurface()->getCanvas()); |
| 266 if (m_isDeferralEnabled) | 324 if (m_isDeferralEnabled) |
| 267 startRecording(); | 325 startRecording(); |
| 268 m_haveRecordedDrawCommands = false; | 326 m_haveRecordedDrawCommands = false; |
| 269 } | 327 } |
| 270 } | 328 } |
| 271 | 329 |
| 272 void Canvas2DLayerBridge::flush() | 330 void Canvas2DLayerBridge::flush() |
| 273 { | 331 { |
| 274 if (!m_surface) | 332 if (!getOrCreateSurface()) |
| 275 return; | 333 return; |
| 276 TRACE_EVENT0("cc", "Canvas2DLayerBridge::flush"); | 334 TRACE_EVENT0("cc", "Canvas2DLayerBridge::flush"); |
| 277 flushRecordingOnly(); | 335 flushRecordingOnly(); |
| 278 m_surface->getCanvas()->flush(); | 336 getOrCreateSurface()->getCanvas()->flush(); |
| 279 } | 337 } |
| 280 | 338 |
| 281 void Canvas2DLayerBridge::flushGpu() | 339 void Canvas2DLayerBridge::flushGpu() |
| 282 { | 340 { |
| 341 TRACE_EVENT0("cc", "Canvas2DLayerBridge::flushGpu"); |
| 283 flush(); | 342 flush(); |
| 284 WebGraphicsContext3D* webContext = context(); | 343 WebGraphicsContext3D* webContext = context(); |
| 285 if (isAccelerated() && webContext) | 344 if (isAccelerated() && webContext) |
| 286 webContext->flush(); | 345 webContext->flush(); |
| 287 } | 346 } |
| 288 | 347 |
| 289 | 348 |
| 290 WebGraphicsContext3D* Canvas2DLayerBridge::context() | 349 WebGraphicsContext3D* Canvas2DLayerBridge::context() |
| 291 { | 350 { |
| 292 // Check on m_layer is necessary because context() may be called during | 351 // Check on m_layer is necessary because context() may be called during |
| 293 // the destruction of m_layer | 352 // the destruction of m_layer |
| 294 if (m_layer && !m_destructionInProgress) | 353 if (m_layer && !m_destructionInProgress) |
| 295 checkSurfaceValid(); // To ensure rate limiter is disabled if context is
lost. | 354 checkSurfaceValid(); // To ensure rate limiter is disabled if context is
lost. |
| 296 return m_contextProvider ? m_contextProvider->context3d() : 0; | 355 return m_contextProvider ? m_contextProvider->context3d() : 0; |
| 297 } | 356 } |
| 298 | 357 |
| 299 bool Canvas2DLayerBridge::checkSurfaceValid() | 358 bool Canvas2DLayerBridge::checkSurfaceValid() |
| 300 { | 359 { |
| 301 ASSERT(!m_destructionInProgress); | 360 ASSERT(!m_destructionInProgress); |
| 302 if (m_destructionInProgress || !m_surface) | 361 if (m_destructionInProgress) |
| 362 return false; |
| 363 if (!m_layer) |
| 364 return true; |
| 365 if (!m_surface) |
| 303 return false; | 366 return false; |
| 304 if (m_contextProvider->context3d()->isContextLost()) { | 367 if (m_contextProvider->context3d()->isContextLost()) { |
| 305 m_surface.clear(); | 368 m_surface.clear(); |
| 306 for (auto mailboxInfo = m_mailboxes.begin(); mailboxInfo != m_mailboxes.
end(); ++mailboxInfo) { | 369 for (auto mailboxInfo = m_mailboxes.begin(); mailboxInfo != m_mailboxes.
end(); ++mailboxInfo) { |
| 307 if (mailboxInfo->m_image) | 370 if (mailboxInfo->m_image) |
| 308 mailboxInfo->m_image.clear(); | 371 mailboxInfo->m_image.clear(); |
| 309 } | 372 } |
| 310 if (m_imageBuffer) | 373 if (m_imageBuffer) |
| 311 m_imageBuffer->notifySurfaceInvalid(); | 374 m_imageBuffer->notifySurfaceInvalid(); |
| 312 } | 375 } |
| 313 return m_surface; | 376 return m_surface; |
| 314 } | 377 } |
| 315 | 378 |
| 316 bool Canvas2DLayerBridge::restoreSurface() | 379 bool Canvas2DLayerBridge::restoreSurface() |
| 317 { | 380 { |
| 318 ASSERT(!m_destructionInProgress); | 381 ASSERT(!m_destructionInProgress); |
| 319 if (m_destructionInProgress) | 382 if (m_destructionInProgress) |
| 320 return false; | 383 return false; |
| 321 ASSERT(m_layer && !m_surface); | 384 ASSERT(isAccelerated() && !m_surface); |
| 322 | 385 |
| 323 WebGraphicsContext3D* sharedContext = 0; | 386 WebGraphicsContext3D* sharedContext = 0; |
| 324 m_layer->clearTexture(); | 387 m_layer->clearTexture(); |
| 325 m_contextProvider = adoptPtr(Platform::current()->createSharedOffscreenGraph
icsContext3DProvider()); | 388 m_contextProvider = adoptPtr(Platform::current()->createSharedOffscreenGraph
icsContext3DProvider()); |
| 326 if (m_contextProvider) | 389 if (m_contextProvider) |
| 327 sharedContext = m_contextProvider->context3d(); | 390 sharedContext = m_contextProvider->context3d(); |
| 328 | 391 |
| 329 if (sharedContext && !sharedContext->isContextLost()) { | 392 if (sharedContext && !sharedContext->isContextLost()) { |
| 330 GrContext* grCtx = m_contextProvider->grContext(); | 393 GrContext* grCtx = m_contextProvider->grContext(); |
| 331 RefPtr<SkSurface> surface(createSkSurface(grCtx, m_size, m_msaaSampleCou
nt, m_opacityMode)); | 394 bool surfaceIsAccelerated; |
| 332 if (surface.get()) { | 395 RefPtr<SkSurface> surface(createSkSurface(grCtx, m_size, m_msaaSampleCou
nt, m_opacityMode, &surfaceIsAccelerated)); |
| 396 // Current paradigm does support switching from accelerated to non-accel
erated, which would be tricky |
| 397 // due to changes to the layer tree, which can only happen at specific t
imes during the document lifecycle. |
| 398 // Therefore, we can only accept the restored surface if it is accelerat
ed. |
| 399 if (surface.get() && surfaceIsAccelerated) { |
| 333 m_surface = surface.release(); | 400 m_surface = surface.release(); |
| 334 m_initialSurfaceSaveCount = m_surface->getCanvas()->getSaveCount(); | |
| 335 // FIXME: draw sad canvas picture into new buffer crbug.com/243842 | 401 // FIXME: draw sad canvas picture into new buffer crbug.com/243842 |
| 336 } | 402 } |
| 337 } | 403 } |
| 338 | 404 |
| 339 return m_surface; | 405 return m_surface; |
| 340 } | 406 } |
| 341 | 407 |
| 342 bool Canvas2DLayerBridge::prepareMailbox(WebExternalTextureMailbox* outMailbox,
WebExternalBitmap* bitmap) | 408 bool Canvas2DLayerBridge::prepareMailbox(WebExternalTextureMailbox* outMailbox,
WebExternalBitmap* bitmap) |
| 343 { | 409 { |
| 410 ASSERT(isAccelerated()); |
| 344 if (m_destructionInProgress) { | 411 if (m_destructionInProgress) { |
| 345 // It can be hit in the following sequence. | 412 // It can be hit in the following sequence. |
| 346 // 1. Canvas draws something. | 413 // 1. Canvas draws something. |
| 347 // 2. The compositor begins the frame. | 414 // 2. The compositor begins the frame. |
| 348 // 3. Javascript makes a context be lost. | 415 // 3. Javascript makes a context be lost. |
| 349 // 4. Here. | 416 // 4. Here. |
| 350 return false; | 417 return false; |
| 351 } | 418 } |
| 352 if (bitmap) { | 419 if (bitmap) { |
| 353 // Using accelerated 2d canvas with software renderer, which | 420 // Using accelerated 2d canvas with software renderer, which |
| 354 // should only happen in tests that use fake graphics contexts | 421 // should only happen in tests that use fake graphics contexts |
| 355 // or in Android WebView in software mode. In this case, we do | 422 // or in Android WebView in software mode. In this case, we do |
| 356 // not care about producing any results for this canvas. | 423 // not care about producing any results for this canvas. |
| 357 skipQueuedDrawCommands(); | 424 skipQueuedDrawCommands(); |
| 358 m_lastImageId = 0; | 425 m_lastImageId = 0; |
| 359 return false; | 426 return false; |
| 360 } | 427 } |
| 361 if (!checkSurfaceValid()) | 428 if (!checkSurfaceValid()) |
| 362 return false; | 429 return false; |
| 363 | 430 |
| 364 WebGraphicsContext3D* webContext = context(); | 431 WebGraphicsContext3D* webContext = context(); |
| 365 | 432 |
| 366 RefPtr<SkImage> image = newImageSnapshot(); | 433 RefPtr<SkImage> image = newImageSnapshot(PreferAcceleration); |
| 367 | 434 |
| 368 // Early exit if canvas was not drawn to since last prepareMailbox | 435 // Early exit if canvas was not drawn to since last prepareMailbox |
| 369 GLenum filter = m_filterQuality == kNone_SkFilterQuality ? GL_NEAREST : GL_L
INEAR; | 436 GLenum filter = m_filterQuality == kNone_SkFilterQuality ? GL_NEAREST : GL_L
INEAR; |
| 370 if (image->uniqueID() == m_lastImageId && filter == m_lastFilter) | 437 if (image->uniqueID() == m_lastImageId && filter == m_lastFilter) |
| 371 return false; | 438 return false; |
| 372 m_lastImageId = image->uniqueID(); | 439 m_lastImageId = image->uniqueID(); |
| 373 m_lastFilter = filter; | 440 m_lastFilter = filter; |
| 374 | 441 |
| 375 { | 442 { |
| 376 MailboxInfo tmp; | 443 MailboxInfo tmp; |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 427 // Because we are changing the texture binding without going through skia, | 494 // Because we are changing the texture binding without going through skia, |
| 428 // we must dirty the context. | 495 // we must dirty the context. |
| 429 grContext->resetContext(kTextureBinding_GrGLBackendState); | 496 grContext->resetContext(kTextureBinding_GrGLBackendState); |
| 430 | 497 |
| 431 *outMailbox = mailboxInfo.m_mailbox; | 498 *outMailbox = mailboxInfo.m_mailbox; |
| 432 return true; | 499 return true; |
| 433 } | 500 } |
| 434 | 501 |
| 435 void Canvas2DLayerBridge::mailboxReleased(const WebExternalTextureMailbox& mailb
ox, bool lostResource) | 502 void Canvas2DLayerBridge::mailboxReleased(const WebExternalTextureMailbox& mailb
ox, bool lostResource) |
| 436 { | 503 { |
| 504 ASSERT(isAccelerated()); |
| 437 bool contextLost = !m_surface || m_contextProvider->context3d()->isContextLo
st(); | 505 bool contextLost = !m_surface || m_contextProvider->context3d()->isContextLo
st(); |
| 438 ASSERT(m_mailboxes.last().m_parentLayerBridge.get() == this); | 506 ASSERT(m_mailboxes.last().m_parentLayerBridge.get() == this); |
| 439 | 507 |
| 440 // Mailboxes are typically released in FIFO order, so we iterate | 508 // Mailboxes are typically released in FIFO order, so we iterate |
| 441 // from the end of m_mailboxes. | 509 // from the end of m_mailboxes. |
| 442 auto releasedMailboxInfo = m_mailboxes.end(); | 510 auto releasedMailboxInfo = m_mailboxes.end(); |
| 443 auto firstMailbox = m_mailboxes.begin(); | 511 auto firstMailbox = m_mailboxes.begin(); |
| 444 | 512 |
| 445 while (true) { | 513 while (true) { |
| 446 --releasedMailboxInfo; | 514 --releasedMailboxInfo; |
| 447 if (nameEquals(releasedMailboxInfo->m_mailbox, mailbox)) { | 515 if (nameEquals(releasedMailboxInfo->m_mailbox, mailbox)) { |
| 448 break; | 516 break; |
| 449 } | 517 } |
| 450 if (releasedMailboxInfo == firstMailbox) { | 518 ASSERT(releasedMailboxInfo != firstMailbox); |
| 451 // Reached last entry without finding a match, should never happen. | |
| 452 // FIXME: This used to be an ASSERT, and was (temporarily?) changed
to a | |
| 453 // CRASH to facilitate the investigation of crbug.com/443898. | |
| 454 CRASH(); | |
| 455 } | |
| 456 } | 519 } |
| 457 | 520 |
| 458 if (!contextLost) { | 521 if (!contextLost) { |
| 459 // Invalidate texture state in case the compositor altered it since the
copy-on-write. | 522 // Invalidate texture state in case the compositor altered it since the
copy-on-write. |
| 460 if (releasedMailboxInfo->m_image) { | 523 if (releasedMailboxInfo->m_image) { |
| 461 if (mailbox.syncPoint) { | 524 if (mailbox.syncPoint) { |
| 462 context()->waitSyncPoint(mailbox.syncPoint); | 525 context()->waitSyncPoint(mailbox.syncPoint); |
| 463 } | 526 } |
| 464 GrTexture* texture = releasedMailboxInfo->m_image->getTexture(); | 527 GrTexture* texture = releasedMailboxInfo->m_image->getTexture(); |
| 465 if (texture) { | 528 if (texture) { |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 503 if (m_recordingPixelCount >= (m_size.width() * m_size.height() * Expensi
veCanvasHeuristicParameters::ExpensiveOverdrawThreshold)) { | 566 if (m_recordingPixelCount >= (m_size.width() * m_size.height() * Expensi
veCanvasHeuristicParameters::ExpensiveOverdrawThreshold)) { |
| 504 disableDeferral(); | 567 disableDeferral(); |
| 505 } | 568 } |
| 506 } | 569 } |
| 507 if (!m_isRegisteredTaskObserver) { | 570 if (!m_isRegisteredTaskObserver) { |
| 508 Platform::current()->currentThread()->addTaskObserver(this); | 571 Platform::current()->currentThread()->addTaskObserver(this); |
| 509 m_isRegisteredTaskObserver = true; | 572 m_isRegisteredTaskObserver = true; |
| 510 } | 573 } |
| 511 } | 574 } |
| 512 | 575 |
| 576 void Canvas2DLayerBridge::prepareSurfaceForPaintingIfNeeded() |
| 577 { |
| 578 getOrCreateSurface(PreferAcceleration); |
| 579 } |
| 580 |
| 513 void Canvas2DLayerBridge::finalizeFrame(const FloatRect &dirtyRect) | 581 void Canvas2DLayerBridge::finalizeFrame(const FloatRect &dirtyRect) |
| 514 { | 582 { |
| 515 ASSERT(!m_destructionInProgress); | 583 ASSERT(!m_destructionInProgress); |
| 516 m_layer->layer()->invalidateRect(enclosingIntRect(dirtyRect)); | 584 if (m_layer) |
| 585 m_layer->layer()->invalidateRect(enclosingIntRect(dirtyRect)); |
| 517 if (m_rateLimiter) | 586 if (m_rateLimiter) |
| 518 m_rateLimiter->reset(); | 587 m_rateLimiter->reset(); |
| 519 m_renderingTaskCompletedForCurrentFrame = false; | 588 m_renderingTaskCompletedForCurrentFrame = false; |
| 520 } | 589 } |
| 521 | 590 |
| 522 void Canvas2DLayerBridge::didProcessTask() | 591 void Canvas2DLayerBridge::didProcessTask() |
| 523 { | 592 { |
| 524 TRACE_EVENT0("cc", "Canvas2DLayerBridge::didProcessTask"); | 593 TRACE_EVENT0("cc", "Canvas2DLayerBridge::didProcessTask"); |
| 525 ASSERT(m_isRegisteredTaskObserver); | 594 ASSERT(m_isRegisteredTaskObserver); |
| 526 // If m_renderTaskProcessedForCurrentFrame is already set to true, | 595 // If m_renderTaskProcessedForCurrentFrame is already set to true, |
| (...skipping 17 matching lines...) Expand all Loading... |
| 544 | 613 |
| 545 m_renderingTaskCompletedForCurrentFrame = true; | 614 m_renderingTaskCompletedForCurrentFrame = true; |
| 546 unregisterTaskObserver(); | 615 unregisterTaskObserver(); |
| 547 } | 616 } |
| 548 | 617 |
| 549 void Canvas2DLayerBridge::willProcessTask() | 618 void Canvas2DLayerBridge::willProcessTask() |
| 550 { | 619 { |
| 551 ASSERT_NOT_REACHED(); | 620 ASSERT_NOT_REACHED(); |
| 552 } | 621 } |
| 553 | 622 |
| 554 PassRefPtr<SkImage> Canvas2DLayerBridge::newImageSnapshot() | 623 PassRefPtr<SkImage> Canvas2DLayerBridge::newImageSnapshot(AccelerationHint hint) |
| 555 { | 624 { |
| 556 if (!checkSurfaceValid()) | 625 if (!checkSurfaceValid()) |
| 557 return nullptr; | 626 return nullptr; |
| 627 getOrCreateSurface(hint); |
| 558 flush(); | 628 flush(); |
| 559 // A readback operation may alter the texture parameters, which may affect | 629 // A readback operation may alter the texture parameters, which may affect |
| 560 // the compositor's behavior. Therefore, we must trigger copy-on-write | 630 // the compositor's behavior. Therefore, we must trigger copy-on-write |
| 561 // even though we are not technically writing to the texture, only to its | 631 // even though we are not technically writing to the texture, only to its |
| 562 // parameters. | 632 // parameters. |
| 563 m_surface->notifyContentWillChange(SkSurface::kRetain_ContentChangeMode); | 633 getOrCreateSurface()->notifyContentWillChange(SkSurface::kRetain_ContentChan
geMode); |
| 564 return adoptRef(m_surface->newImageSnapshot()); | 634 return adoptRef(m_surface->newImageSnapshot()); |
| 565 } | 635 } |
| 566 | 636 |
| 567 void Canvas2DLayerBridge::willOverwriteCanvas() | 637 void Canvas2DLayerBridge::willOverwriteCanvas() |
| 568 { | 638 { |
| 569 skipQueuedDrawCommands(); | 639 skipQueuedDrawCommands(); |
| 570 } | 640 } |
| 571 | 641 |
| 572 Canvas2DLayerBridge::MailboxInfo::MailboxInfo(const MailboxInfo& other) { | 642 Canvas2DLayerBridge::MailboxInfo::MailboxInfo(const MailboxInfo& other) |
| 643 { |
| 573 memcpy(&m_mailbox, &other.m_mailbox, sizeof(m_mailbox)); | 644 memcpy(&m_mailbox, &other.m_mailbox, sizeof(m_mailbox)); |
| 574 m_image = other.m_image; | 645 m_image = other.m_image; |
| 575 m_parentLayerBridge = other.m_parentLayerBridge; | 646 m_parentLayerBridge = other.m_parentLayerBridge; |
| 576 } | 647 } |
| 577 | 648 |
| 578 } // namespace blink | 649 } // namespace blink |
| OLD | NEW |