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