Chromium Code Reviews| 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..a91ffa7e1523178abb63919d88ad5f66db14005a |
| --- /dev/null |
| +++ b/third_party/WebKit/Source/platform/graphics/gpu/ImageLayerBridge.cpp |
| @@ -0,0 +1,172 @@ |
| +// 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 "public/platform/Platform.h" |
| +#include "public/platform/WebCompositorSupport.h" |
| +#include "public/platform/WebExternalTextureLayer.h" |
| + |
| +namespace blink { |
| + |
| +ImageLayerBridge::ImageLayerBridge(OpacityMode opacityMode) |
| + : m_weakPtrFactory(this), m_opacityMode(opacityMode) {} |
| + |
| +ImageLayerBridge::~ImageLayerBridge() { |
| + if (!m_disposed) |
| + dispose(); |
| +} |
| + |
| +void ImageLayerBridge::setImage(PassRefPtr<StaticBitmapImage> image) { |
| + if (!m_layer) { |
| + 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); |
|
xlai (Olivia)
2017/03/09 21:57:27
Do you need to consider the "premultiplied alpha"
Justin Novosad
2017/03/10 21:09:59
Turns out I don't. Premul is assumed here. FWIW,
|
| + } |
| + } |
| + m_image = std::move(image); |
| + if (m_image) { |
| + if (m_opacityMode == NonOpaque) { |
| + m_layer->setOpaque(m_image->currentFrameKnownToBeOpaque()); |
| + m_layer->setBlendBackgroundColor(!m_image->currentFrameKnownToBeOpaque()); |
| + } |
| + } |
| + m_layer->layer()->invalidate(); |
| + 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(ColorBehavior::tag()) |
| + ->getTextureHandle(true); // triggers a GrContext flush if needed. |
| + } |
| + 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; |
| + |
| + m_hasPresentedSinceLastSetImage = true; |
| + |
| + if (m_image->isAccelerated()) { |
| + 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(ColorBehavior::tag()); |
| + 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++) { |
|
xlai (Olivia)
2017/03/09 21:57:27
Why do you do this loop? The source (x, y) seems t
Justin Novosad
2017/03/10 21:09:59
This is to do a y-flip on the image data. For som
|
| + 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->isAccelerated()); |
| + DCHECK(image->hasMailbox()); |
| + if (token.HasData()) { |
| + image->updateSyncToken(token); |
| + } |
| + } |
| + // 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 |