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