Index: third_party/WebKit/Source/platform/graphics/gpu/ImageLayerBridge.cpp |
diff --git a/third_party/WebKit/Source/platform/graphics/gpu/ImageLayerBridge.cpp b/third_party/WebKit/Source/platform/graphics/gpu/ImageLayerBridge.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..e31bc9bc3e5aacebf5337479754acf07e35b8c5f |
--- /dev/null |
+++ b/third_party/WebKit/Source/platform/graphics/gpu/ImageLayerBridge.cpp |
@@ -0,0 +1,181 @@ |
+// Copyright 2017 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "platform/graphics/gpu/ImageLayerBridge.h" |
+ |
+#include "cc/resources/shared_bitmap.h" |
+#include "cc/resources/texture_mailbox.h" |
+#include "gpu/command_buffer/client/gles2_interface.h" |
+#include "platform/graphics/ColorBehavior.h" |
+#include "platform/graphics/GraphicsLayer.h" |
+#include "platform/graphics/gpu/SharedGpuContext.h" |
+#include "public/platform/Platform.h" |
+#include "public/platform/WebCompositorSupport.h" |
+#include "public/platform/WebExternalTextureLayer.h" |
+#include "public/platform/WebGraphicsContext3DProvider.h" |
+ |
+namespace blink { |
+ |
+ImageLayerBridge::ImageLayerBridge(OpacityMode opacityMode) |
+ : m_weakPtrFactory(this), m_opacityMode(opacityMode) { |
+ m_layer = |
+ Platform::current()->compositorSupport()->createExternalTextureLayer( |
+ this); |
+ GraphicsLayer::registerContentsLayer(m_layer->layer()); |
+ m_layer->setNearestNeighbor(m_filterQuality == kNone_SkFilterQuality); |
+ if (m_opacityMode == Opaque) { |
+ m_layer->setOpaque(true); |
+ m_layer->setBlendBackgroundColor(false); |
+ } |
+} |
+ |
+ImageLayerBridge::~ImageLayerBridge() { |
+ if (!m_disposed) |
+ dispose(); |
+} |
+ |
+void ImageLayerBridge::setImage(PassRefPtr<StaticBitmapImage> image) { |
+ m_image = std::move(image); |
+ if (m_image) { |
+ if (m_opacityMode == NonOpaque) { |
+ m_layer->setOpaque(m_image->currentFrameKnownToBeOpaque()); |
+ m_layer->setBlendBackgroundColor(!m_image->currentFrameKnownToBeOpaque()); |
+ } |
+ } |
+ if (!m_hasPresentedSinceLastSetImage && m_image && |
+ m_image->isTextureBacked()) { |
+ // If the layer bridge is not presenting, the GrContext may not be getting |
+ // flushed regularly. The flush is normally triggered inside the |
+ // m_image->ensureMailbox() call of |
+ // ImageLayerBridge::PrepareTextureMailbox. To prevent a potential memory |
+ // leak we must flush the GrContext here. |
+ m_image->imageForCurrentFrame()->getTextureHandle( |
+ true); // GrContext flush. |
+ } |
+ m_hasPresentedSinceLastSetImage = false; |
+} |
+ |
+void ImageLayerBridge::dispose() { |
+ if (m_layer) { |
+ GraphicsLayer::unregisterContentsLayer(m_layer->layer()); |
+ m_layer->clearTexture(); |
+ m_layer.reset(); |
+ } |
+ m_image = nullptr; |
+ m_disposed = true; |
+} |
+ |
+bool ImageLayerBridge::PrepareTextureMailbox( |
+ cc::TextureMailbox* outMailbox, |
+ std::unique_ptr<cc::SingleReleaseCallback>* outReleaseCallback) { |
+ if (m_disposed) |
+ return false; |
+ |
+ if (!m_image) |
+ return false; |
+ |
+ if (m_hasPresentedSinceLastSetImage) |
+ return false; |
+ |
+ m_hasPresentedSinceLastSetImage = true; |
+ |
+ if (m_image->isTextureBacked()) { |
+ m_image->ensureMailbox(); |
+ *outMailbox = cc::TextureMailbox(m_image->mailbox(), m_image->syncToken(), |
+ GL_TEXTURE_2D); |
+ auto func = WTF::bind(&ImageLayerBridge::mailboxReleasedGpu, |
+ m_weakPtrFactory.createWeakPtr(), m_image); |
+ *outReleaseCallback = cc::SingleReleaseCallback::Create( |
+ convertToBaseCallback(std::move(func))); |
+ } else { |
+ std::unique_ptr<cc::SharedBitmap> bitmap = createOrRecycleBitmap(); |
+ if (!bitmap) |
+ return false; |
+ |
+ sk_sp<SkImage> skImage = m_image->imageForCurrentFrame(); |
+ if (!skImage) |
+ return false; |
+ |
+ SkImageInfo dstInfo = SkImageInfo::MakeN32Premul(m_image->width(), 1); |
+ size_t rowBytes = m_image->width() * 4; |
+ |
+ // loop to flip Y |
+ for (int row = 0; row < m_image->height(); row++) { |
+ if (!skImage->readPixels( |
+ dstInfo, |
+ bitmap->pixels() + rowBytes * (m_image->height() - 1 - row), |
+ rowBytes, 0, row)) |
+ return false; |
+ } |
+ |
+ *outMailbox = cc::TextureMailbox( |
+ bitmap.get(), gfx::Size(m_image->width(), m_image->height())); |
+ auto func = WTF::bind(&ImageLayerBridge::mailboxReleasedSoftware, |
+ m_weakPtrFactory.createWeakPtr(), |
+ base::Passed(&bitmap), m_image->size()); |
+ *outReleaseCallback = cc::SingleReleaseCallback::Create( |
+ convertToBaseCallback(std::move(func))); |
+ } |
+ |
+ outMailbox->set_nearest_neighbor(m_filterQuality == kNone_SkFilterQuality); |
+ // TODO(junov): Figure out how to get the color space info. |
+ // outMailbox->set_color_space(); |
+ |
+ return true; |
+} |
+ |
+std::unique_ptr<cc::SharedBitmap> ImageLayerBridge::createOrRecycleBitmap() { |
+ auto it = std::remove_if(m_recycledBitmaps.begin(), m_recycledBitmaps.end(), |
+ [this](const RecycledBitmap& bitmap) { |
+ return bitmap.size != m_image->size(); |
+ }); |
+ m_recycledBitmaps.shrink(it - m_recycledBitmaps.begin()); |
+ |
+ if (!m_recycledBitmaps.isEmpty()) { |
+ RecycledBitmap recycled = std::move(m_recycledBitmaps.back()); |
+ m_recycledBitmaps.pop_back(); |
+ DCHECK(recycled.size == m_image->size()); |
+ return std::move(recycled.bitmap); |
+ } |
+ return Platform::current()->allocateSharedBitmap(m_image->size()); |
+} |
+ |
+void ImageLayerBridge::mailboxReleasedGpu(RefPtr<StaticBitmapImage> image, |
+ const gpu::SyncToken& token, |
+ bool lostResource) { |
+ if (image) { |
+ DCHECK(image->isTextureBacked()); |
+ if (token.HasData()) { |
+ if (image->hasMailbox()) { |
+ image->updateSyncToken(token); |
+ } else { |
+ // Wait on sync token now because SkiaTextureHolder does not know |
+ // about sync tokens. |
+ gpu::gles2::GLES2Interface* sharedGL = SharedGpuContext::gl(); |
+ if (sharedGL) |
+ sharedGL->WaitSyncTokenCHROMIUM(token.GetConstData()); |
+ } |
+ } |
+ } |
+ // let 'image' go out of scope to finalize the release. The |
+ // destructor will wait on sync token before deleting resource. |
+} |
+ |
+void ImageLayerBridge::mailboxReleasedSoftware( |
+ std::unique_ptr<cc::SharedBitmap> bitmap, |
+ const IntSize& size, |
+ const gpu::SyncToken& syncToken, |
+ bool lostResource) { |
+ DCHECK(!syncToken.HasData()); // No sync tokens for software resources. |
+ if (!m_disposed && !lostResource) { |
+ RecycledBitmap recycled = {std::move(bitmap), size}; |
+ m_recycledBitmaps.push_back(std::move(recycled)); |
+ } |
+} |
+ |
+WebLayer* ImageLayerBridge::platformLayer() const { |
+ return m_layer->layer(); |
+} |
+ |
+} // namespace blink |