| 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..c36bbda5bcae13265cd1c417edc8dc82c903bd97
|
| --- /dev/null
|
| +++ b/third_party/WebKit/Source/platform/graphics/gpu/ImageLayerBridge.cpp
|
| @@ -0,0 +1,182 @@
|
| +// 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"
|
| +
|
| +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);
|
| + }
|
| + }
|
| + 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()->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->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();
|
| + 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->isAccelerated());
|
| + 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
|
|
|