| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright (C) 2012 Google Inc. All rights reserved. | |
| 3 * | |
| 4 * Redistribution and use in source and binary forms, with or without | |
| 5 * modification, are permitted provided that the following conditions | |
| 6 * are met: | |
| 7 * | |
| 8 * 1. Redistributions of source code must retain the above copyright | |
| 9 * notice, this list of conditions and the following disclaimer. | |
| 10 * 2. Redistributions in binary form must reproduce the above copyright | |
| 11 * notice, this list of conditions and the following disclaimer in the | |
| 12 * documentation and/or other materials provided with the distribution. | |
| 13 * | |
| 14 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY | |
| 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
| 16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
| 17 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY | |
| 18 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
| 19 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
| 20 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
| 21 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
| 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 24 */ | |
| 25 | |
| 26 | |
| 27 #include "sky/engine/platform/graphics/Canvas2DLayerBridge.h" | |
| 28 | |
| 29 #include "sky/engine/platform/TraceEvent.h" | |
| 30 #include "sky/engine/platform/graphics/Canvas2DLayerManager.h" | |
| 31 #include "sky/engine/platform/graphics/ImageBuffer.h" | |
| 32 #include "sky/engine/public/platform/Platform.h" | |
| 33 #include "sky/engine/public/platform/WebGraphicsContext3D.h" | |
| 34 #include "sky/engine/public/platform/WebGraphicsContext3DProvider.h" | |
| 35 #include "sky/engine/wtf/RefCountedLeakCounter.h" | |
| 36 #include "third_party/skia/include/core/SkDevice.h" | |
| 37 #include "third_party/skia/include/core/SkSurface.h" | |
| 38 #include "third_party/skia/include/gpu/GrContext.h" | |
| 39 | |
| 40 namespace { | |
| 41 enum { | |
| 42 InvalidMailboxIndex = -1, | |
| 43 }; | |
| 44 | |
| 45 DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, canvas2DLayerBridgeInstance
Counter, ("Canvas2DLayerBridge")); | |
| 46 } | |
| 47 | |
| 48 namespace blink { | |
| 49 | |
| 50 static PassRefPtr<SkSurface> createSkSurface(GrContext* gr, const IntSize& size,
int msaaSampleCount = 0) | |
| 51 { | |
| 52 if (!gr) | |
| 53 return nullptr; | |
| 54 gr->resetContext(); | |
| 55 SkImageInfo info = SkImageInfo::MakeN32Premul(size.width(), size.height()); | |
| 56 SkSurfaceProps disableLCDProps(0, kUnknown_SkPixelGeometry); | |
| 57 return adoptRef(SkSurface::NewRenderTarget(gr, SkSurface::kNo_Budgeted, info
, msaaSampleCount, &disableLCDProps)); | |
| 58 } | |
| 59 | |
| 60 PassRefPtr<Canvas2DLayerBridge> Canvas2DLayerBridge::create(const IntSize& size,
OpacityMode opacityMode, int msaaSampleCount) | |
| 61 { | |
| 62 TRACE_EVENT_INSTANT0("test_gpu", "Canvas2DLayerBridgeCreation", TRACE_EVENT_
SCOPE_NAME_PROCESS); | |
| 63 OwnPtr<WebGraphicsContext3DProvider> contextProvider = adoptPtr(Platform::cu
rrent()->createSharedOffscreenGraphicsContext3DProvider()); | |
| 64 if (!contextProvider) | |
| 65 return nullptr; | |
| 66 RefPtr<SkSurface> surface(createSkSurface(contextProvider->grContext(), size
, msaaSampleCount)); | |
| 67 if (!surface) | |
| 68 return nullptr; | |
| 69 RefPtr<Canvas2DLayerBridge> layerBridge; | |
| 70 OwnPtr<SkDeferredCanvas> canvas = adoptPtr(SkDeferredCanvas::Create(surface.
get())); | |
| 71 layerBridge = adoptRef(new Canvas2DLayerBridge(contextProvider.release(), ca
nvas.release(), surface.release(), msaaSampleCount, opacityMode)); | |
| 72 return layerBridge.release(); | |
| 73 } | |
| 74 | |
| 75 Canvas2DLayerBridge::Canvas2DLayerBridge(PassOwnPtr<WebGraphicsContext3DProvider
> contextProvider, PassOwnPtr<SkDeferredCanvas> canvas, PassRefPtr<SkSurface> su
rface, int msaaSampleCount, OpacityMode opacityMode) | |
| 76 : m_canvas(canvas) | |
| 77 , m_surface(surface) | |
| 78 , m_contextProvider(contextProvider) | |
| 79 , m_imageBuffer(0) | |
| 80 , m_msaaSampleCount(msaaSampleCount) | |
| 81 , m_bytesAllocated(0) | |
| 82 , m_didRecordDrawCommand(false) | |
| 83 , m_isSurfaceValid(true) | |
| 84 , m_framesPending(0) | |
| 85 , m_framesSinceMailboxRelease(0) | |
| 86 , m_destructionInProgress(false) | |
| 87 , m_rateLimitingEnabled(false) | |
| 88 , m_isHidden(false) | |
| 89 , m_next(0) | |
| 90 , m_prev(0) | |
| 91 , m_lastImageId(0) | |
| 92 , m_releasedMailboxInfoIndex(InvalidMailboxIndex) | |
| 93 { | |
| 94 ASSERT(m_canvas); | |
| 95 ASSERT(m_surface); | |
| 96 ASSERT(m_contextProvider); | |
| 97 // Used by browser tests to detect the use of a Canvas2DLayerBridge. | |
| 98 TRACE_EVENT_INSTANT0("test_gpu", "Canvas2DLayerBridgeCreation", TRACE_EVENT_
SCOPE_NAME_PROCESS); | |
| 99 m_layer = nullptr; | |
| 100 CRASH(); // No compositor. | |
| 101 m_layer->setOpaque(opacityMode == Opaque); | |
| 102 m_layer->setBlendBackgroundColor(opacityMode != Opaque); | |
| 103 m_layer->setRateLimitContext(m_rateLimitingEnabled); | |
| 104 m_canvas->setNotificationClient(this); | |
| 105 #ifndef NDEBUG | |
| 106 canvas2DLayerBridgeInstanceCounter.increment(); | |
| 107 #endif | |
| 108 } | |
| 109 | |
| 110 Canvas2DLayerBridge::~Canvas2DLayerBridge() | |
| 111 { | |
| 112 ASSERT(m_destructionInProgress); | |
| 113 ASSERT(!Canvas2DLayerManager::get().isInList(this)); | |
| 114 m_layer.clear(); | |
| 115 freeReleasedMailbox(); | |
| 116 #if ENABLE(ASSERT) | |
| 117 Vector<MailboxInfo>::iterator mailboxInfo; | |
| 118 for (mailboxInfo = m_mailboxes.begin(); mailboxInfo < m_mailboxes.end(); ++m
ailboxInfo) { | |
| 119 ASSERT(mailboxInfo->m_status != MailboxInUse); | |
| 120 ASSERT(mailboxInfo->m_status != MailboxReleased || m_contextProvider->co
ntext3d()->isContextLost() || !m_isSurfaceValid); | |
| 121 } | |
| 122 #endif | |
| 123 m_mailboxes.clear(); | |
| 124 #ifndef NDEBUG | |
| 125 canvas2DLayerBridgeInstanceCounter.decrement(); | |
| 126 #endif | |
| 127 } | |
| 128 | |
| 129 void Canvas2DLayerBridge::beginDestruction() | |
| 130 { | |
| 131 ASSERT(!m_destructionInProgress); | |
| 132 setRateLimitingEnabled(false); | |
| 133 m_canvas->silentFlush(); | |
| 134 m_imageBuffer = 0; | |
| 135 freeTransientResources(); | |
| 136 setIsHidden(true); | |
| 137 m_destructionInProgress = true; | |
| 138 m_canvas->setNotificationClient(0); | |
| 139 m_surface.clear(); | |
| 140 m_canvas.clear(); | |
| 141 m_layer->clearTexture(); | |
| 142 // Orphaning the layer is required to trigger the recration of a new layer | |
| 143 // in the case where destruction is caused by a canvas resize. Test: | |
| 144 // virtual/gpu/fast/canvas/canvas-resize-after-paint-without-layout.html | |
| 145 m_layer->layer()->removeFromParent(); | |
| 146 // To anyone who ever hits this assert: Please update crbug.com/344666 | |
| 147 // with repro steps. | |
| 148 ASSERT(!m_bytesAllocated); | |
| 149 } | |
| 150 | |
| 151 void Canvas2DLayerBridge::setIsHidden(bool hidden) | |
| 152 { | |
| 153 ASSERT(!m_destructionInProgress); | |
| 154 bool newHiddenValue = hidden || m_destructionInProgress; | |
| 155 if (m_isHidden == newHiddenValue) | |
| 156 return; | |
| 157 | |
| 158 m_isHidden = newHiddenValue; | |
| 159 if (isHidden()) { | |
| 160 freeTransientResources(); | |
| 161 } | |
| 162 } | |
| 163 | |
| 164 void Canvas2DLayerBridge::willAccessPixels() | |
| 165 { | |
| 166 // A readback operation may alter the texture parameters, which may affect | |
| 167 // the compositor's behavior. Therefore, we must trigger copy-on-write | |
| 168 // even though we are not technically writing to the texture, only to its | |
| 169 // parameters. | |
| 170 m_surface->notifyContentWillChange(SkSurface::kRetain_ContentChangeMode); | |
| 171 } | |
| 172 | |
| 173 void Canvas2DLayerBridge::freeTransientResources() | |
| 174 { | |
| 175 ASSERT(!m_destructionInProgress); | |
| 176 if (!m_isSurfaceValid) | |
| 177 return; | |
| 178 freeReleasedMailbox(); | |
| 179 flush(); | |
| 180 freeMemoryIfPossible(bytesAllocated()); | |
| 181 ASSERT(!hasTransientResources()); | |
| 182 } | |
| 183 | |
| 184 bool Canvas2DLayerBridge::hasTransientResources() const | |
| 185 { | |
| 186 return !m_destructionInProgress && (hasReleasedMailbox() || bytesAllocated()
); | |
| 187 } | |
| 188 | |
| 189 void Canvas2DLayerBridge::limitPendingFrames() | |
| 190 { | |
| 191 ASSERT(!m_destructionInProgress); | |
| 192 if (isHidden()) { | |
| 193 freeTransientResources(); | |
| 194 return; | |
| 195 } | |
| 196 if (m_didRecordDrawCommand) { | |
| 197 m_framesPending++; | |
| 198 m_didRecordDrawCommand = false; | |
| 199 if (m_framesPending > 1) { | |
| 200 // Turn on the rate limiter if this layer tends to accumulate a | |
| 201 // non-discardable multi-frame backlog of draw commands. | |
| 202 setRateLimitingEnabled(true); | |
| 203 } | |
| 204 if (m_rateLimitingEnabled) { | |
| 205 flush(); | |
| 206 } | |
| 207 } | |
| 208 ++m_framesSinceMailboxRelease; | |
| 209 if (releasedMailboxHasExpired()) { | |
| 210 freeReleasedMailbox(); | |
| 211 } | |
| 212 } | |
| 213 | |
| 214 void Canvas2DLayerBridge::prepareForDraw() | |
| 215 { | |
| 216 ASSERT(!m_destructionInProgress); | |
| 217 ASSERT(m_layer); | |
| 218 if (!checkSurfaceValid()) { | |
| 219 if (m_canvas) { | |
| 220 // drop pending commands because there is no surface to draw to | |
| 221 m_canvas->silentFlush(); | |
| 222 } | |
| 223 return; | |
| 224 } | |
| 225 } | |
| 226 | |
| 227 void Canvas2DLayerBridge::storageAllocatedForRecordingChanged(size_t bytesAlloca
ted) | |
| 228 { | |
| 229 ASSERT(!m_destructionInProgress); | |
| 230 intptr_t delta = (intptr_t)bytesAllocated - (intptr_t)m_bytesAllocated; | |
| 231 m_bytesAllocated = bytesAllocated; | |
| 232 Canvas2DLayerManager::get().layerTransientResourceAllocationChanged(this, de
lta); | |
| 233 } | |
| 234 | |
| 235 size_t Canvas2DLayerBridge::storageAllocatedForRecording() | |
| 236 { | |
| 237 return m_canvas->storageAllocatedForRecording(); | |
| 238 } | |
| 239 | |
| 240 void Canvas2DLayerBridge::flushedDrawCommands() | |
| 241 { | |
| 242 ASSERT(!m_destructionInProgress); | |
| 243 storageAllocatedForRecordingChanged(storageAllocatedForRecording()); | |
| 244 m_framesPending = 0; | |
| 245 } | |
| 246 | |
| 247 void Canvas2DLayerBridge::skippedPendingDrawCommands() | |
| 248 { | |
| 249 ASSERT(!m_destructionInProgress); | |
| 250 // Stop triggering the rate limiter if SkDeferredCanvas is detecting | |
| 251 // and optimizing overdraw. | |
| 252 setRateLimitingEnabled(false); | |
| 253 flushedDrawCommands(); | |
| 254 } | |
| 255 | |
| 256 void Canvas2DLayerBridge::setRateLimitingEnabled(bool enabled) | |
| 257 { | |
| 258 ASSERT(!m_destructionInProgress); | |
| 259 if (m_rateLimitingEnabled != enabled) { | |
| 260 m_rateLimitingEnabled = enabled; | |
| 261 m_layer->setRateLimitContext(m_rateLimitingEnabled); | |
| 262 } | |
| 263 } | |
| 264 | |
| 265 size_t Canvas2DLayerBridge::freeMemoryIfPossible(size_t bytesToFree) | |
| 266 { | |
| 267 ASSERT(!m_destructionInProgress); | |
| 268 size_t bytesFreed = m_canvas->freeMemoryIfPossible(bytesToFree); | |
| 269 m_bytesAllocated -= bytesFreed; | |
| 270 if (bytesFreed) | |
| 271 Canvas2DLayerManager::get().layerTransientResourceAllocationChanged(this
, -((intptr_t)bytesFreed)); | |
| 272 return bytesFreed; | |
| 273 } | |
| 274 | |
| 275 void Canvas2DLayerBridge::flush() | |
| 276 { | |
| 277 ASSERT(!m_destructionInProgress); | |
| 278 if (m_canvas->hasPendingCommands()) { | |
| 279 TRACE_EVENT0("cc", "Canvas2DLayerBridge::flush"); | |
| 280 freeReleasedMailbox(); // To avoid unnecessary triple-buffering | |
| 281 m_canvas->flush(); | |
| 282 } | |
| 283 } | |
| 284 | |
| 285 bool Canvas2DLayerBridge::releasedMailboxHasExpired() | |
| 286 { | |
| 287 // This heuristic indicates that the canvas is not being | |
| 288 // actively presented by the compositor (3 frames rendered since | |
| 289 // last mailbox release), suggesting that double buffering is not required. | |
| 290 return hasReleasedMailbox() && m_framesSinceMailboxRelease > 2; | |
| 291 } | |
| 292 | |
| 293 Canvas2DLayerBridge::MailboxInfo* Canvas2DLayerBridge::releasedMailboxInfo() | |
| 294 { | |
| 295 return hasReleasedMailbox() ? &m_mailboxes[m_releasedMailboxInfoIndex] : 0; | |
| 296 } | |
| 297 | |
| 298 bool Canvas2DLayerBridge::hasReleasedMailbox() const | |
| 299 { | |
| 300 return m_releasedMailboxInfoIndex != InvalidMailboxIndex; | |
| 301 } | |
| 302 | |
| 303 void Canvas2DLayerBridge::freeReleasedMailbox() | |
| 304 { | |
| 305 if (!m_isSurfaceValid || m_contextProvider->context3d()->isContextLost()) | |
| 306 return; | |
| 307 MailboxInfo* mailboxInfo = releasedMailboxInfo(); | |
| 308 if (!mailboxInfo) | |
| 309 return; | |
| 310 | |
| 311 ASSERT(mailboxInfo->m_status == MailboxReleased); | |
| 312 if (mailboxInfo->m_mailbox.syncPoint) { | |
| 313 context()->waitSyncPoint(mailboxInfo->m_mailbox.syncPoint); | |
| 314 mailboxInfo->m_mailbox.syncPoint = 0; | |
| 315 } | |
| 316 // Invalidate texture state in case the compositor altered it since the copy
-on-write. | |
| 317 if (mailboxInfo->m_image) { | |
| 318 mailboxInfo->m_image->getTexture()->textureParamsModified(); | |
| 319 mailboxInfo->m_image.clear(); | |
| 320 } | |
| 321 mailboxInfo->m_status = MailboxAvailable; | |
| 322 m_releasedMailboxInfoIndex = InvalidMailboxIndex; | |
| 323 Canvas2DLayerManager::get().layerTransientResourceAllocationChanged(this); | |
| 324 } | |
| 325 | |
| 326 WebGraphicsContext3D* Canvas2DLayerBridge::context() | |
| 327 { | |
| 328 // Check on m_layer is necessary because context() may be called during | |
| 329 // the destruction of m_layer | |
| 330 if (m_layer && !m_destructionInProgress) | |
| 331 checkSurfaceValid(); // To ensure rate limiter is disabled if context is
lost. | |
| 332 return m_contextProvider ? m_contextProvider->context3d() : 0; | |
| 333 } | |
| 334 | |
| 335 bool Canvas2DLayerBridge::checkSurfaceValid() | |
| 336 { | |
| 337 ASSERT(!m_destructionInProgress); | |
| 338 if (m_destructionInProgress || !m_isSurfaceValid) | |
| 339 return false; | |
| 340 if (m_contextProvider->context3d()->isContextLost()) { | |
| 341 m_isSurfaceValid = false; | |
| 342 m_surface.clear(); | |
| 343 if (m_imageBuffer) | |
| 344 m_imageBuffer->notifySurfaceInvalid(); | |
| 345 setRateLimitingEnabled(false); | |
| 346 } | |
| 347 return m_isSurfaceValid; | |
| 348 } | |
| 349 | |
| 350 bool Canvas2DLayerBridge::restoreSurface() | |
| 351 { | |
| 352 ASSERT(!m_destructionInProgress); | |
| 353 if (m_destructionInProgress) | |
| 354 return false; | |
| 355 ASSERT(m_layer && !m_isSurfaceValid); | |
| 356 | |
| 357 WebGraphicsContext3D* sharedContext = 0; | |
| 358 // We must clear the mailboxes before calling m_layer->clearTexture() to pre
vent | |
| 359 // re-entry via mailboxReleased from operating on defunct GrContext objects. | |
| 360 m_mailboxes.clear(); | |
| 361 m_releasedMailboxInfoIndex = InvalidMailboxIndex; | |
| 362 m_layer->clearTexture(); | |
| 363 m_contextProvider = adoptPtr(Platform::current()->createSharedOffscreenGraph
icsContext3DProvider()); | |
| 364 if (m_contextProvider) | |
| 365 sharedContext = m_contextProvider->context3d(); | |
| 366 | |
| 367 if (sharedContext && !sharedContext->isContextLost()) { | |
| 368 IntSize size(m_canvas->getTopDevice()->width(), m_canvas->getTopDevice()
->height()); | |
| 369 RefPtr<SkSurface> surface(createSkSurface(m_contextProvider->grContext()
, size, m_msaaSampleCount)); | |
| 370 if (surface.get()) { | |
| 371 m_surface = surface.release(); | |
| 372 m_canvas->setSurface(m_surface.get()); | |
| 373 m_isSurfaceValid = true; | |
| 374 // FIXME: draw sad canvas picture into new buffer crbug.com/243842 | |
| 375 } | |
| 376 } | |
| 377 | |
| 378 return m_isSurfaceValid; | |
| 379 } | |
| 380 | |
| 381 bool Canvas2DLayerBridge::prepareMailbox(WebExternalTextureMailbox* outMailbox,
WebExternalBitmap* bitmap) | |
| 382 { | |
| 383 if (m_destructionInProgress) { | |
| 384 // It can be hit in the following sequence. | |
| 385 // 1. Canvas draws something. | |
| 386 // 2. The compositor begins the frame. | |
| 387 // 3. Javascript makes a context be lost. | |
| 388 // 4. Here. | |
| 389 return false; | |
| 390 } | |
| 391 if (bitmap) { | |
| 392 // Using accelerated 2d canvas with software renderer, which | |
| 393 // should only happen in tests that use fake graphics contexts | |
| 394 // or in Android WebView in software mode. In this case, we do | |
| 395 // not care about producing any results for this canvas. | |
| 396 m_canvas->silentFlush(); | |
| 397 m_lastImageId = 0; | |
| 398 return false; | |
| 399 } | |
| 400 if (!checkSurfaceValid()) | |
| 401 return false; | |
| 402 | |
| 403 WebGraphicsContext3D* webContext = context(); | |
| 404 | |
| 405 // Release to skia textures that were previouosly released by the | |
| 406 // compositor. We do this before acquiring the next snapshot in | |
| 407 // order to cap maximum gpu memory consumption. | |
| 408 flush(); | |
| 409 | |
| 410 RefPtr<SkImage> image = adoptRef(m_canvas->newImageSnapshot()); | |
| 411 | |
| 412 // Early exit if canvas was not drawn to since last prepareMailbox | |
| 413 if (image->uniqueID() == m_lastImageId) | |
| 414 return false; | |
| 415 m_lastImageId = image->uniqueID(); | |
| 416 | |
| 417 MailboxInfo* mailboxInfo = createMailboxInfo(); | |
| 418 mailboxInfo->m_status = MailboxInUse; | |
| 419 mailboxInfo->m_image = image; | |
| 420 | |
| 421 ASSERT(mailboxInfo->m_mailbox.syncPoint == 0); | |
| 422 ASSERT(mailboxInfo->m_image.get()); | |
| 423 ASSERT(mailboxInfo->m_image->getTexture()); | |
| 424 | |
| 425 // Because of texture sharing with the compositor, we must invalidate | |
| 426 // the state cached in skia so that the deferred copy on write | |
| 427 // in SkSurface_Gpu does not make any false assumptions. | |
| 428 mailboxInfo->m_image->getTexture()->textureParamsModified(); | |
| 429 | |
| 430 webContext->bindTexture(GL_TEXTURE_2D, mailboxInfo->m_image->getTexture()->g
etTextureHandle()); | |
| 431 webContext->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
| 432 webContext->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
| 433 webContext->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE
); | |
| 434 webContext->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE
); | |
| 435 webContext->produceTextureCHROMIUM(GL_TEXTURE_2D, mailboxInfo->m_mailbox.nam
e); | |
| 436 if (isHidden()) { | |
| 437 // With hidden canvases, we release the SkImage immediately because | |
| 438 // there is no need for animations to be double buffered. | |
| 439 mailboxInfo->m_image.clear(); | |
| 440 } else { | |
| 441 webContext->flush(); | |
| 442 mailboxInfo->m_mailbox.syncPoint = webContext->insertSyncPoint(); | |
| 443 } | |
| 444 webContext->bindTexture(GL_TEXTURE_2D, 0); | |
| 445 // Because we are changing the texture binding without going through skia, | |
| 446 // we must dirty the context. | |
| 447 m_contextProvider->grContext()->resetContext(kTextureBinding_GrGLBackendStat
e); | |
| 448 | |
| 449 // set m_parentLayerBridge to make sure 'this' stays alive as long as it has | |
| 450 // live mailboxes | |
| 451 ASSERT(!mailboxInfo->m_parentLayerBridge); | |
| 452 mailboxInfo->m_parentLayerBridge = this; | |
| 453 *outMailbox = mailboxInfo->m_mailbox; | |
| 454 | |
| 455 return true; | |
| 456 } | |
| 457 | |
| 458 Canvas2DLayerBridge::MailboxInfo* Canvas2DLayerBridge::createMailboxInfo() { | |
| 459 ASSERT(!m_destructionInProgress); | |
| 460 MailboxInfo* mailboxInfo; | |
| 461 for (mailboxInfo = m_mailboxes.begin(); mailboxInfo < m_mailboxes.end(); mai
lboxInfo++) { | |
| 462 if (mailboxInfo->m_status == MailboxAvailable) { | |
| 463 return mailboxInfo; | |
| 464 } | |
| 465 } | |
| 466 | |
| 467 // No available mailbox: create one. | |
| 468 m_mailboxes.grow(m_mailboxes.size() + 1); | |
| 469 mailboxInfo = &m_mailboxes.last(); | |
| 470 context()->genMailboxCHROMIUM(mailboxInfo->m_mailbox.name); | |
| 471 // Worst case, canvas is triple buffered. More than 3 active mailboxes | |
| 472 // means there is a problem. | |
| 473 // For the single-threaded case, this value needs to be at least | |
| 474 // kMaxSwapBuffersPending+1 (in render_widget.h). | |
| 475 // Because of crbug.com/247874, it needs to be kMaxSwapBuffersPending+2. | |
| 476 // TODO(piman): fix this. | |
| 477 ASSERT(m_mailboxes.size() <= 4); | |
| 478 ASSERT(mailboxInfo < m_mailboxes.end()); | |
| 479 return mailboxInfo; | |
| 480 } | |
| 481 | |
| 482 void Canvas2DLayerBridge::mailboxReleased(const WebExternalTextureMailbox& mailb
ox, bool lostResource) | |
| 483 { | |
| 484 freeReleasedMailbox(); // Never have more than one mailbox in the released s
tate. | |
| 485 bool contextLost = !m_isSurfaceValid || m_contextProvider->context3d()->isCo
ntextLost(); | |
| 486 Vector<MailboxInfo>::iterator mailboxInfo; | |
| 487 for (mailboxInfo = m_mailboxes.begin(); mailboxInfo < m_mailboxes.end(); ++m
ailboxInfo) { | |
| 488 if (nameEquals(mailboxInfo->m_mailbox, mailbox)) { | |
| 489 mailboxInfo->m_mailbox.syncPoint = mailbox.syncPoint; | |
| 490 ASSERT(mailboxInfo->m_status == MailboxInUse); | |
| 491 ASSERT(mailboxInfo->m_parentLayerBridge.get() == this); | |
| 492 | |
| 493 if (contextLost) { | |
| 494 // No need to clean up the mailbox resource, but make sure the | |
| 495 // mailbox can also be reusable once the context is restored. | |
| 496 mailboxInfo->m_status = MailboxAvailable; | |
| 497 m_releasedMailboxInfoIndex = InvalidMailboxIndex; | |
| 498 Canvas2DLayerManager::get().layerTransientResourceAllocationChan
ged(this); | |
| 499 } else if (lostResource) { | |
| 500 // In case of the resource is lost, we need to delete the backin
g | |
| 501 // texture and remove the mailbox from list to avoid reusing it | |
| 502 // in future. | |
| 503 if (mailboxInfo->m_image) { | |
| 504 GrTexture* texture = mailboxInfo->m_image->getTexture(); | |
| 505 if (texture) | |
| 506 texture->textureParamsModified(); | |
| 507 mailboxInfo->m_image.clear(); | |
| 508 } | |
| 509 size_t i = mailboxInfo - m_mailboxes.begin(); | |
| 510 m_mailboxes.remove(i); | |
| 511 Canvas2DLayerManager::get().layerTransientResourceAllocationChan
ged(this); | |
| 512 // Here we need to return early since mailboxInfo removal would | |
| 513 // also clear m_parentLayerBridge reference. | |
| 514 return; | |
| 515 } else { | |
| 516 mailboxInfo->m_status = MailboxReleased; | |
| 517 m_releasedMailboxInfoIndex = mailboxInfo - m_mailboxes.begin(); | |
| 518 m_framesSinceMailboxRelease = 0; | |
| 519 if (isHidden()) { | |
| 520 freeReleasedMailbox(); | |
| 521 } else { | |
| 522 ASSERT(!m_destructionInProgress); | |
| 523 Canvas2DLayerManager::get().layerTransientResourceAllocation
Changed(this); | |
| 524 } | |
| 525 } | |
| 526 // Trigger Canvas2DLayerBridge self-destruction if this is the | |
| 527 // last live mailbox and the layer bridge is not externally | |
| 528 // referenced. | |
| 529 mailboxInfo->m_parentLayerBridge.clear(); | |
| 530 return; | |
| 531 } | |
| 532 } | |
| 533 } | |
| 534 | |
| 535 WebLayer* Canvas2DLayerBridge::layer() const | |
| 536 { | |
| 537 ASSERT(!m_destructionInProgress); | |
| 538 ASSERT(m_layer); | |
| 539 return m_layer->layer(); | |
| 540 } | |
| 541 | |
| 542 void Canvas2DLayerBridge::finalizeFrame() | |
| 543 { | |
| 544 ASSERT(!m_destructionInProgress); | |
| 545 Canvas2DLayerManager::get().layerDidDraw(this); | |
| 546 m_didRecordDrawCommand = true; | |
| 547 } | |
| 548 | |
| 549 Platform3DObject Canvas2DLayerBridge::getBackingTexture() | |
| 550 { | |
| 551 ASSERT(!m_destructionInProgress); | |
| 552 if (!checkSurfaceValid()) | |
| 553 return 0; | |
| 554 m_canvas->flush(); | |
| 555 context()->flush(); | |
| 556 GrRenderTarget* renderTarget = m_canvas->getTopDevice()->accessRenderTarget(
); | |
| 557 if (renderTarget) { | |
| 558 return renderTarget->asTexture()->getTextureHandle(); | |
| 559 } | |
| 560 return 0; | |
| 561 } | |
| 562 | |
| 563 Canvas2DLayerBridge::MailboxInfo::MailboxInfo(const MailboxInfo& other) { | |
| 564 // This copy constructor should only be used for Vector reallocation | |
| 565 // Assuming 'other' is to be destroyed, we transfer m_image and | |
| 566 // m_parentLayerBridge ownership rather than do a refcount dance. | |
| 567 memcpy(&m_mailbox, &other.m_mailbox, sizeof(m_mailbox)); | |
| 568 m_image = const_cast<MailboxInfo*>(&other)->m_image.release(); | |
| 569 m_parentLayerBridge = const_cast<MailboxInfo*>(&other)->m_parentLayerBridge.
release(); | |
| 570 m_status = other.m_status; | |
| 571 } | |
| 572 | |
| 573 } // namespace blink | |
| OLD | NEW |