Index: Source/core/platform/graphics/Canvas2DLayerBridge.cpp |
diff --git a/Source/core/platform/graphics/Canvas2DLayerBridge.cpp b/Source/core/platform/graphics/Canvas2DLayerBridge.cpp |
deleted file mode 100644 |
index f7e911ca33b2d907134986ca2b647367234e92f9..0000000000000000000000000000000000000000 |
--- a/Source/core/platform/graphics/Canvas2DLayerBridge.cpp |
+++ /dev/null |
@@ -1,425 +0,0 @@ |
-/* |
- * Copyright (C) 2012 Google Inc. All rights reserved. |
- * |
- * Redistribution and use in source and binary forms, with or without |
- * modification, are permitted provided that the following conditions |
- * are met: |
- * |
- * 1. Redistributions of source code must retain the above copyright |
- * notice, this list of conditions and the following disclaimer. |
- * 2. Redistributions in binary form must reproduce the above copyright |
- * notice, this list of conditions and the following disclaimer in the |
- * documentation and/or other materials provided with the distribution. |
- * |
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY |
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY |
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
- */ |
- |
-#include "config.h" |
- |
-#include "core/platform/graphics/Canvas2DLayerBridge.h" |
- |
-#include "GrContext.h" |
-#include "SkDevice.h" |
-#include "SkSurface.h" |
-#include "core/platform/graphics/Canvas2DLayerManager.h" |
-#include "core/platform/graphics/GraphicsLayer.h" |
-#include "core/platform/graphics/gpu/SharedGraphicsContext3D.h" |
-#include "platform/TraceEvent.h" |
-#include "public/platform/Platform.h" |
-#include "public/platform/WebCompositorSupport.h" |
-#include "public/platform/WebGraphicsContext3D.h" |
- |
-using blink::WebExternalTextureLayer; |
-using blink::WebGraphicsContext3D; |
- |
-namespace WebCore { |
- |
-void Canvas2DLayerBridgePtr::clear() |
-{ |
- if (m_ptr) { |
- m_ptr->destroy(); |
- m_ptr.clear(); |
- } |
-} |
- |
-Canvas2DLayerBridgePtr& Canvas2DLayerBridgePtr::operator=(const PassRefPtr<Canvas2DLayerBridge>& other) |
-{ |
- clear(); |
- m_ptr = other; |
- return *this; |
-} |
- |
-static SkSurface* createSurface(GraphicsContext3D* context3D, const IntSize& size, int msaaSampleCount) |
-{ |
- ASSERT(!context3D->webContext()->isContextLost()); |
- GrContext* gr = context3D->grContext(); |
- if (!gr) |
- return 0; |
- gr->resetContext(); |
- SkImageInfo info; |
- info.fWidth = size.width(); |
- info.fHeight = size.height(); |
- info.fColorType = kPMColor_SkColorType; |
- info.fAlphaType = kPremul_SkAlphaType; |
- return SkSurface::NewRenderTarget(gr, info, msaaSampleCount); |
-} |
- |
-PassRefPtr<Canvas2DLayerBridge> Canvas2DLayerBridge::create(PassRefPtr<GraphicsContext3D> context, const IntSize& size, OpacityMode opacityMode, int msaaSampleCount) |
-{ |
- TRACE_EVENT_INSTANT0("test_gpu", "Canvas2DLayerBridgeCreation"); |
- SkAutoTUnref<SkSurface> surface(createSurface(context.get(), size, msaaSampleCount)); |
- if (!surface.get()) { |
- return PassRefPtr<Canvas2DLayerBridge>(); |
- } |
- RefPtr<SkDeferredCanvas> canvas = adoptRef(SkDeferredCanvas::Create(surface.get())); |
- RefPtr<Canvas2DLayerBridge> layerBridge = adoptRef(new Canvas2DLayerBridge(context, canvas.release(), msaaSampleCount, opacityMode)); |
- return layerBridge.release(); |
-} |
- |
-Canvas2DLayerBridge::Canvas2DLayerBridge(PassRefPtr<GraphicsContext3D> context, PassRefPtr<SkDeferredCanvas> canvas, int msaaSampleCount, OpacityMode opacityMode) |
- : m_canvas(canvas) |
- , m_context(context) |
- , m_msaaSampleCount(msaaSampleCount) |
- , m_bytesAllocated(0) |
- , m_didRecordDrawCommand(false) |
- , m_surfaceIsValid(true) |
- , m_framesPending(0) |
- , m_destructionInProgress(false) |
- , m_rateLimitingEnabled(false) |
- , m_next(0) |
- , m_prev(0) |
- , m_lastImageId(0) |
-{ |
- ASSERT(m_canvas); |
- // Used by browser tests to detect the use of a Canvas2DLayerBridge. |
- TRACE_EVENT_INSTANT0("test_gpu", "Canvas2DLayerBridgeCreation"); |
- m_layer = adoptPtr(blink::Platform::current()->compositorSupport()->createExternalTextureLayer(this)); |
- m_layer->setOpaque(opacityMode == Opaque); |
- m_layer->setBlendBackgroundColor(opacityMode != Opaque); |
- GraphicsLayer::registerContentsLayer(m_layer->layer()); |
- m_layer->setRateLimitContext(m_rateLimitingEnabled); |
- m_canvas->setNotificationClient(this); |
-} |
- |
-Canvas2DLayerBridge::~Canvas2DLayerBridge() |
-{ |
- ASSERT(m_destructionInProgress); |
- m_layer.clear(); |
- Vector<MailboxInfo>::iterator mailboxInfo; |
- for (mailboxInfo = m_mailboxes.begin(); mailboxInfo < m_mailboxes.end(); mailboxInfo++) { |
- ASSERT(mailboxInfo->m_status != MailboxInUse); |
- if (mailboxInfo->m_status == MailboxReleased) { |
- if (mailboxInfo->m_mailbox.syncPoint) { |
- context()->waitSyncPoint(mailboxInfo->m_mailbox.syncPoint); |
- mailboxInfo->m_mailbox.syncPoint = 0; |
- } |
- // Invalidate texture state in case the compositor altered it since the copy-on-write. |
- mailboxInfo->m_image->getTexture()->invalidateCachedState(); |
- } |
- } |
- m_mailboxes.clear(); |
-} |
- |
-void Canvas2DLayerBridge::destroy() |
-{ |
- ASSERT(!m_destructionInProgress); |
- m_destructionInProgress = true; |
- GraphicsLayer::unregisterContentsLayer(m_layer->layer()); |
- m_canvas->setNotificationClient(0); |
- m_layer->clearTexture(); |
- Canvas2DLayerManager::get().layerToBeDestroyed(this); |
- // Orphaning the layer is required to trigger the recration of a new layer |
- // in the case where destruction is caused by a canvas resize. Test: |
- // virtual/gpu/fast/canvas/canvas-resize-after-paint-without-layout.html |
- m_layer->layer()->removeFromParent(); |
-} |
- |
-void Canvas2DLayerBridge::limitPendingFrames() |
-{ |
- ASSERT(!m_destructionInProgress); |
- if (m_didRecordDrawCommand) { |
- m_framesPending++; |
- m_didRecordDrawCommand = false; |
- if (m_framesPending > 1) { |
- // Turn on the rate limiter if this layer tends to accumulate a |
- // non-discardable multi-frame backlog of draw commands. |
- setRateLimitingEnabled(true); |
- } |
- if (m_rateLimitingEnabled) { |
- flush(); |
- } |
- } |
-} |
- |
-void Canvas2DLayerBridge::prepareForDraw() |
-{ |
- ASSERT(!m_destructionInProgress); |
- ASSERT(m_layer); |
- if (!isValid()) { |
- if (m_canvas) { |
- // drop pending commands because there is no surface to draw to |
- m_canvas->silentFlush(); |
- } |
- return; |
- } |
- m_context->makeContextCurrent(); |
-} |
- |
-void Canvas2DLayerBridge::storageAllocatedForRecordingChanged(size_t bytesAllocated) |
-{ |
- ASSERT(!m_destructionInProgress); |
- intptr_t delta = (intptr_t)bytesAllocated - (intptr_t)m_bytesAllocated; |
- m_bytesAllocated = bytesAllocated; |
- Canvas2DLayerManager::get().layerAllocatedStorageChanged(this, delta); |
-} |
- |
-size_t Canvas2DLayerBridge::storageAllocatedForRecording() |
-{ |
- ASSERT(!m_destructionInProgress); |
- return m_canvas->storageAllocatedForRecording(); |
-} |
- |
-void Canvas2DLayerBridge::flushedDrawCommands() |
-{ |
- ASSERT(!m_destructionInProgress); |
- storageAllocatedForRecordingChanged(storageAllocatedForRecording()); |
- m_framesPending = 0; |
-} |
- |
-void Canvas2DLayerBridge::skippedPendingDrawCommands() |
-{ |
- ASSERT(!m_destructionInProgress); |
- // Stop triggering the rate limiter if SkDeferredCanvas is detecting |
- // and optimizing overdraw. |
- setRateLimitingEnabled(false); |
- flushedDrawCommands(); |
-} |
- |
-void Canvas2DLayerBridge::setRateLimitingEnabled(bool enabled) |
-{ |
- ASSERT(!m_destructionInProgress || !enabled); |
- if (m_rateLimitingEnabled != enabled) { |
- m_rateLimitingEnabled = enabled; |
- m_layer->setRateLimitContext(m_rateLimitingEnabled); |
- } |
-} |
- |
-size_t Canvas2DLayerBridge::freeMemoryIfPossible(size_t bytesToFree) |
-{ |
- ASSERT(!m_destructionInProgress); |
- size_t bytesFreed = m_canvas->freeMemoryIfPossible(bytesToFree); |
- if (bytesFreed) |
- Canvas2DLayerManager::get().layerAllocatedStorageChanged(this, -((intptr_t)bytesFreed)); |
- m_bytesAllocated -= bytesFreed; |
- return bytesFreed; |
-} |
- |
-void Canvas2DLayerBridge::flush() |
-{ |
- ASSERT(!m_destructionInProgress); |
- if (m_canvas->hasPendingCommands()) { |
- TRACE_EVENT0("cc", "Canvas2DLayerBridge::flush"); |
- m_canvas->flush(); |
- } |
-} |
- |
-WebGraphicsContext3D* Canvas2DLayerBridge::context() |
-{ |
- // Check on m_layer is necessary because context() may be called during |
- // the destruction of m_layer |
- if (m_layer) { |
- isValid(); // To ensure rate limiter is disabled if context is lost. |
- } |
- return m_context->webContext(); |
-} |
- |
-bool Canvas2DLayerBridge::isValid() |
-{ |
- ASSERT(m_layer); |
- if (m_destructionInProgress) |
- return false; |
- if (m_context->webContext()->isContextLost() || !m_surfaceIsValid) { |
- // Attempt to recover. |
- m_layer->clearTexture(); |
- m_mailboxes.clear(); |
- RefPtr<GraphicsContext3D> sharedContext = SharedGraphicsContext3D::get(); |
- if (!sharedContext || sharedContext->webContext()->isContextLost()) { |
- m_surfaceIsValid = false; |
- } else { |
- m_context = sharedContext; |
- IntSize size(m_canvas->getTopDevice()->width(), m_canvas->getTopDevice()->height()); |
- SkAutoTUnref<SkSurface> surface(createSurface(m_context.get(), size, m_msaaSampleCount)); |
- if (surface.get()) { |
- m_canvas->setSurface(surface.get()); |
- m_surfaceIsValid = true; |
- // FIXME: draw sad canvas picture into new buffer crbug.com/243842 |
- } else { |
- // Surface allocation failed. Set m_surfaceIsValid to false to |
- // trigger subsequent retry. |
- m_surfaceIsValid = false; |
- } |
- } |
- } |
- if (!m_surfaceIsValid) |
- setRateLimitingEnabled(false); |
- return m_surfaceIsValid; |
-} |
- |
-bool Canvas2DLayerBridge::prepareMailbox(blink::WebExternalTextureMailbox* outMailbox, blink::WebExternalBitmap* bitmap) |
-{ |
- if (bitmap) { |
- // Using accelerated 2d canvas with software renderer, which |
- // should only happen in tests that use fake graphics contexts. |
- // In this case, we do not care about producing any results for |
- // compositing. |
- m_canvas->silentFlush(); |
- return false; |
- } |
- if (!isValid()) |
- return false; |
- // Release to skia textures that were previouosly released by the |
- // compositor. We do this before acquiring the next snapshot in |
- // order to cap maximum gpu memory consumption. |
- m_context->makeContextCurrent(); |
- flush(); |
- Vector<MailboxInfo>::iterator mailboxInfo; |
- for (mailboxInfo = m_mailboxes.begin(); mailboxInfo < m_mailboxes.end(); mailboxInfo++) { |
- if (mailboxInfo->m_status == MailboxReleased) { |
- if (mailboxInfo->m_mailbox.syncPoint) { |
- context()->waitSyncPoint(mailboxInfo->m_mailbox.syncPoint); |
- mailboxInfo->m_mailbox.syncPoint = 0; |
- } |
- // Invalidate texture state in case the compositor altered it since the copy-on-write. |
- mailboxInfo->m_image->getTexture()->invalidateCachedState(); |
- mailboxInfo->m_image.reset(0); |
- mailboxInfo->m_status = MailboxAvailable; |
- } |
- } |
- SkAutoTUnref<SkImage> image(m_canvas->newImageSnapshot()); |
- // Early exit if canvas was not drawn to since last prepareMailbox |
- if (image->uniqueID() == m_lastImageId) |
- return false; |
- m_lastImageId = image->uniqueID(); |
- |
- mailboxInfo = createMailboxInfo(); |
- mailboxInfo->m_status = MailboxInUse; |
- mailboxInfo->m_image.swap(&image); |
- // Because of texture sharing with the compositor, we must invalidate |
- // the state cached in skia so that the deferred copy on write |
- // in SkSurface_Gpu does not make any false assumptions. |
- mailboxInfo->m_image->getTexture()->invalidateCachedState(); |
- |
- ASSERT(mailboxInfo->m_mailbox.syncPoint == 0); |
- ASSERT(mailboxInfo->m_image.get()); |
- ASSERT(mailboxInfo->m_image->getTexture()); |
- |
- m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, mailboxInfo->m_image->getTexture()->getTextureHandle()); |
- m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::LINEAR); |
- m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::LINEAR); |
- m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_S, GraphicsContext3D::CLAMP_TO_EDGE); |
- m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::CLAMP_TO_EDGE); |
- context()->produceTextureCHROMIUM(GraphicsContext3D::TEXTURE_2D, mailboxInfo->m_mailbox.name); |
- context()->flush(); |
- mailboxInfo->m_mailbox.syncPoint = context()->insertSyncPoint(); |
- m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, 0); |
- // Because we are changing the texture binding without going through skia, |
- // we must dirty the context. |
- m_context->grContext()->resetContext(kTextureBinding_GrGLBackendState); |
- |
- // set m_parentLayerBridge to make sure 'this' stays alive as long as it has |
- // live mailboxes |
- ASSERT(!mailboxInfo->m_parentLayerBridge); |
- mailboxInfo->m_parentLayerBridge = this; |
- *outMailbox = mailboxInfo->m_mailbox; |
- return true; |
-} |
- |
-Canvas2DLayerBridge::MailboxInfo* Canvas2DLayerBridge::createMailboxInfo() { |
- ASSERT(!m_destructionInProgress); |
- MailboxInfo* mailboxInfo; |
- for (mailboxInfo = m_mailboxes.begin(); mailboxInfo < m_mailboxes.end(); mailboxInfo++) { |
- if (mailboxInfo->m_status == MailboxAvailable) { |
- return mailboxInfo; |
- } |
- } |
- |
- // No available mailbox: create one. |
- m_mailboxes.grow(m_mailboxes.size() + 1); |
- mailboxInfo = &m_mailboxes.last(); |
- context()->genMailboxCHROMIUM(mailboxInfo->m_mailbox.name); |
- // Worst case, canvas is triple buffered. More than 3 active mailboxes |
- // means there is a problem. |
- // For the single-threaded case, this value needs to be at least |
- // kMaxSwapBuffersPending+1 (in render_widget.h). |
- // Because of crbug.com/247874, it needs to be kMaxSwapBuffersPending+2. |
- // TODO(piman): fix this. |
- ASSERT(m_mailboxes.size() <= 4); |
- ASSERT(mailboxInfo < m_mailboxes.end()); |
- return mailboxInfo; |
-} |
- |
-void Canvas2DLayerBridge::mailboxReleased(const blink::WebExternalTextureMailbox& mailbox) |
-{ |
- Vector<MailboxInfo>::iterator mailboxInfo; |
- for (mailboxInfo = m_mailboxes.begin(); mailboxInfo < m_mailboxes.end(); mailboxInfo++) { |
- if (!memcmp(mailboxInfo->m_mailbox.name, mailbox.name, sizeof(mailbox.name))) { |
- mailboxInfo->m_mailbox.syncPoint = mailbox.syncPoint; |
- ASSERT(mailboxInfo->m_status == MailboxInUse); |
- mailboxInfo->m_status = MailboxReleased; |
- // Trigger Canvas2DLayerBridge self-destruction if this is the |
- // last live mailbox and the layer bridge is not externally |
- // referenced. |
- ASSERT(mailboxInfo->m_parentLayerBridge.get() == this); |
- mailboxInfo->m_parentLayerBridge.clear(); |
- return; |
- } |
- } |
-} |
- |
-blink::WebLayer* Canvas2DLayerBridge::layer() |
-{ |
- ASSERT(m_layer); |
- return m_layer->layer(); |
-} |
- |
-void Canvas2DLayerBridge::contextAcquired() |
-{ |
- ASSERT(!m_destructionInProgress); |
- Canvas2DLayerManager::get().layerDidDraw(this); |
- m_didRecordDrawCommand = true; |
-} |
- |
-unsigned Canvas2DLayerBridge::backBufferTexture() |
-{ |
- ASSERT(!m_destructionInProgress); |
- if (!isValid()) |
- return 0; |
- contextAcquired(); |
- m_canvas->flush(); |
- m_context->flush(); |
- GrRenderTarget* renderTarget = reinterpret_cast<GrRenderTarget*>(m_canvas->getDevice()->accessRenderTarget()); |
- if (renderTarget) { |
- return renderTarget->asTexture()->getTextureHandle(); |
- } |
- return 0; |
-} |
- |
-Canvas2DLayerBridge::MailboxInfo::MailboxInfo(const MailboxInfo& other) { |
- // This copy constructor should only be used for Vector reallocation |
- // Assuming 'other' is to be destroyed, we swap m_image ownership |
- // rather than do a refcount dance. |
- memcpy(&m_mailbox, &other.m_mailbox, sizeof(m_mailbox)); |
- m_image.swap(const_cast<SkAutoTUnref<SkImage>*>(&other.m_image)); |
- m_status = other.m_status; |
-} |
- |
-} |