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

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

Issue 1372463002: Re-land: Make 2D canvas smarter about chosing whether or not to use GPU acceleration (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fixed assert Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2012 Google Inc. All rights reserved. 2 * Copyright (C) 2012 Google Inc. All rights reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions 5 * modification, are permitted provided that the following conditions
6 * are met: 6 * are met:
7 * 7 *
8 * 1. Redistributions of source code must retain the above copyright 8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer. 9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright 10 * 2. Redistributions in binary form must reproduce the above copyright
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698