blob: 4f10d77054f57cb2fb7543166a1b343b90cf05b0 [file] [log] [blame]
// Copyright 2016 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 "third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.h"
#include "components/viz/common/resources/single_release_callback.h"
#include "gpu/GLES2/gl2extchromium.h"
#include "gpu/command_buffer/client/gles2_interface.h"
#include "gpu/command_buffer/common/sync_token.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/web_graphics_context_3d_provider.h"
#include "third_party/blink/renderer/platform/cross_thread_functional.h"
#include "third_party/blink/renderer/platform/graphics/gpu/shared_gpu_context.h"
#include "third_party/blink/renderer/platform/graphics/mailbox_texture_holder.h"
#include "third_party/blink/renderer/platform/graphics/skia/skia_utils.h"
#include "third_party/blink/renderer/platform/graphics/skia_texture_holder.h"
#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
#include "third_party/skia/include/core/SkImage.h"
#include "third_party/skia/include/gpu/GrTexture.h"
#include <memory>
#include <utility>
namespace blink {
scoped_refptr<AcceleratedStaticBitmapImage>
AcceleratedStaticBitmapImage::CreateFromSkImage(
sk_sp<SkImage> image,
base::WeakPtr<WebGraphicsContext3DProviderWrapper>
context_provider_wrapper) {
CHECK(image && image->isTextureBacked());
return base::AdoptRef(new AcceleratedStaticBitmapImage(
std::move(image), std::move(context_provider_wrapper)));
}
scoped_refptr<AcceleratedStaticBitmapImage>
AcceleratedStaticBitmapImage::CreateFromWebGLContextImage(
const gpu::Mailbox& mailbox,
const gpu::SyncToken& sync_token,
unsigned texture_id,
base::WeakPtr<WebGraphicsContext3DProviderWrapper>&&
context_provider_wrapper,
IntSize mailbox_size,
MailboxType mailbox_type,
std::unique_ptr<viz::SingleReleaseCallback> release_callback) {
return base::AdoptRef(new AcceleratedStaticBitmapImage(
mailbox, sync_token, texture_id, std::move(context_provider_wrapper),
mailbox_size, mailbox_type, std::move(release_callback)));
}
AcceleratedStaticBitmapImage::AcceleratedStaticBitmapImage(
sk_sp<SkImage> image,
base::WeakPtr<WebGraphicsContext3DProviderWrapper>&&
context_provider_wrapper)
: paint_image_content_id_(cc::PaintImage::GetNextContentId()),
mailbox_type_(MailboxType::kDeprecatedMailbox) {
CHECK(image && image->isTextureBacked());
texture_holder_ = std::make_unique<SkiaTextureHolder>(
std::move(image), std::move(context_provider_wrapper));
}
AcceleratedStaticBitmapImage::AcceleratedStaticBitmapImage(
const gpu::Mailbox& mailbox,
const gpu::SyncToken& sync_token,
unsigned texture_id,
base::WeakPtr<WebGraphicsContext3DProviderWrapper>&&
context_provider_wrapper,
IntSize mailbox_size,
MailboxType mailbox_type,
std::unique_ptr<viz::SingleReleaseCallback> release_callback)
: paint_image_content_id_(cc::PaintImage::GetNextContentId()),
mailbox_type_(mailbox_type),
release_callback_(std::move(release_callback)) {
texture_holder_ = std::make_unique<MailboxTextureHolder>(
mailbox, sync_token, texture_id, std::move(context_provider_wrapper),
mailbox_size);
}
namespace {
void DestroySkImageOnOriginalThread(
sk_sp<SkImage> image,
base::WeakPtr<WebGraphicsContext3DProviderWrapper> context_provider_wrapper,
std::unique_ptr<gpu::SyncToken> sync_token) {
if (context_provider_wrapper &&
image->isValid(
context_provider_wrapper->ContextProvider()->GetGrContext())) {
if (sync_token->HasData()) {
// To make sure skia does not recycle the texture while it is still in use
// by another context.
context_provider_wrapper->ContextProvider()
->ContextGL()
->WaitSyncTokenCHROMIUM(sync_token->GetData());
}
// In case texture was used by compositor, which may have changed params.
image->getTexture()->textureParamsModified();
}
image.reset();
}
} // unnamed namespace
AcceleratedStaticBitmapImage::~AcceleratedStaticBitmapImage() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
if (release_callback_) {
release_callback_->Run(texture_holder_->GetSyncToken(),
false /* is_lost */);
}
// If the original SkImage was retained, it must be destroyed on the thread
// where it came from. In the same thread case, there is nothing to do because
// the regular destruction flow is fine.
if (original_skia_image_) {
std::unique_ptr<gpu::SyncToken> sync_token =
base::WrapUnique(new gpu::SyncToken(texture_holder_->GetSyncToken()));
if (!original_skia_image_task_runner_->BelongsToCurrentThread()) {
PostCrossThreadTask(
*original_skia_image_task_runner_, FROM_HERE,
CrossThreadBind(
&DestroySkImageOnOriginalThread, std::move(original_skia_image_),
std::move(original_skia_image_context_provider_wrapper_),
WTF::Passed(std::move(sync_token))));
} else {
DestroySkImageOnOriginalThread(
std::move(original_skia_image_),
std::move(original_skia_image_context_provider_wrapper_),
std::move(sync_token));
}
}
}
void AcceleratedStaticBitmapImage::RetainOriginalSkImage() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(texture_holder_->IsSkiaTextureHolder());
original_skia_image_ = texture_holder_->GetSkImage();
original_skia_image_context_provider_wrapper_ = ContextProviderWrapper();
DCHECK(original_skia_image_);
original_skia_image_task_runner_ = Thread::Current()->GetTaskRunner();
}
IntSize AcceleratedStaticBitmapImage::Size() const {
return texture_holder_->Size();
}
scoped_refptr<StaticBitmapImage>
AcceleratedStaticBitmapImage::MakeUnaccelerated() {
CreateImageFromMailboxIfNeeded();
return StaticBitmapImage::Create(
texture_holder_->GetSkImage()->makeNonTextureImage());
}
void AcceleratedStaticBitmapImage::UpdateSyncToken(gpu::SyncToken sync_token) {
texture_holder_->UpdateSyncToken(sync_token);
}
bool AcceleratedStaticBitmapImage::CopyToTexture(
gpu::gles2::GLES2Interface* dest_gl,
GLenum dest_target,
GLuint dest_texture_id,
GLint dest_level,
bool unpack_premultiply_alpha,
bool unpack_flip_y,
const IntPoint& dest_point,
const IntRect& source_sub_rectangle) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
if (!IsValid())
return false;
// This method should only be used for cross-context copying, otherwise it's
// wasting overhead.
DCHECK(texture_holder_->IsCrossThread() ||
dest_gl != ContextProviderWrapper()->ContextProvider()->ContextGL());
// TODO(junov) : could reduce overhead by using kOrderingBarrier when we know
// that the source and destination context or on the same stream.
EnsureMailbox(kUnverifiedSyncToken, GL_NEAREST);
// Get a texture id that |destProvider| knows about and copy from it.
dest_gl->WaitSyncTokenCHROMIUM(
texture_holder_->GetSyncToken().GetConstData());
GLuint source_texture_id;
if (mailbox_type_ == MailboxType::kSharedImageId) {
source_texture_id = dest_gl->CreateAndTexStorage2DSharedImageCHROMIUM(
texture_holder_->GetMailbox().name);
dest_gl->BeginSharedImageAccessDirectCHROMIUM(
source_texture_id, GL_SHARED_IMAGE_ACCESS_MODE_READ_CHROMIUM);
} else {
source_texture_id = dest_gl->CreateAndConsumeTextureCHROMIUM(
texture_holder_->GetMailbox().name);
}
dest_gl->CopySubTextureCHROMIUM(
source_texture_id, 0, dest_target, dest_texture_id, dest_level,
dest_point.X(), dest_point.Y(), source_sub_rectangle.X(),
source_sub_rectangle.Y(), source_sub_rectangle.Width(),
source_sub_rectangle.Height(), unpack_flip_y ? GL_FALSE : GL_TRUE,
GL_FALSE, unpack_premultiply_alpha ? GL_FALSE : GL_TRUE);
if (mailbox_type_ == MailboxType::kSharedImageId) {
dest_gl->EndSharedImageAccessDirectCHROMIUM(source_texture_id);
}
// This drops the |destGL| context's reference on our |m_mailbox|, but it's
// still held alive by our SkImage.
dest_gl->DeleteTextures(1, &source_texture_id);
// We need to update the texture holder's sync token to ensure that when this
// image is deleted, the texture resource will not be recycled by skia before
// the above texture copy has completed.
gpu::SyncToken sync_token;
dest_gl->GenUnverifiedSyncTokenCHROMIUM(sync_token.GetData());
texture_holder_->UpdateSyncToken(sync_token);
return true;
}
PaintImage AcceleratedStaticBitmapImage::PaintImageForCurrentFrame() {
// TODO(ccameron): This function should not ignore |colorBehavior|.
// https://crbug.com/672306
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
if (!IsValid())
return PaintImage();
sk_sp<SkImage> image;
if (original_skia_image_ &&
original_skia_image_task_runner_->BelongsToCurrentThread()) {
// We need to avoid consuming the mailbox in the context where it
// originated. This avoids swapping back and forth between TextureHolder
// types.
image = original_skia_image_;
} else {
CreateImageFromMailboxIfNeeded();
image = texture_holder_->GetSkImage();
}
return CreatePaintImageBuilder()
.set_image(image, paint_image_content_id_)
.set_completion_state(PaintImage::CompletionState::DONE)
.TakePaintImage();
}
void AcceleratedStaticBitmapImage::Draw(cc::PaintCanvas* canvas,
const cc::PaintFlags& flags,
const FloatRect& dst_rect,
const FloatRect& src_rect,
RespectImageOrientationEnum,
ImageClampingMode image_clamping_mode,
ImageDecodingMode decode_mode) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
auto paint_image = PaintImageForCurrentFrame();
if (!paint_image)
return;
auto paint_image_decoding_mode = ToPaintImageDecodingMode(decode_mode);
if (paint_image.decoding_mode() != paint_image_decoding_mode) {
paint_image = PaintImageBuilder::WithCopy(std::move(paint_image))
.set_decoding_mode(paint_image_decoding_mode)
.TakePaintImage();
}
StaticBitmapImage::DrawHelper(canvas, flags, dst_rect, src_rect,
image_clamping_mode, paint_image);
}
bool AcceleratedStaticBitmapImage::IsValid() const {
return texture_holder_ && texture_holder_->IsValid();
}
WebGraphicsContext3DProvider* AcceleratedStaticBitmapImage::ContextProvider()
const {
if (!IsValid())
return nullptr;
return texture_holder_->ContextProvider();
}
base::WeakPtr<WebGraphicsContext3DProviderWrapper>
AcceleratedStaticBitmapImage::ContextProviderWrapper() const {
if (!IsValid())
return nullptr;
return texture_holder_->ContextProviderWrapper();
}
void AcceleratedStaticBitmapImage::CreateImageFromMailboxIfNeeded() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
if (texture_holder_->IsSkiaTextureHolder())
return;
const bool backed_by_shared_image =
mailbox_type_ == MailboxType::kSharedImageId;
texture_holder_ = std::make_unique<SkiaTextureHolder>(
std::move(texture_holder_), backed_by_shared_image);
}
void AcceleratedStaticBitmapImage::EnsureMailbox(MailboxSyncMode mode,
GLenum filter) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
if (!texture_holder_->IsMailboxTextureHolder()) {
TRACE_EVENT0("blink", "AcceleratedStaticBitmapImage::EnsureMailbox");
if (!original_skia_image_) {
// To ensure that the texture resource stays alive we only really need
// to retain the source SkImage until the mailbox is consumed, but this
// works too.
RetainOriginalSkImage();
}
texture_holder_ = std::make_unique<MailboxTextureHolder>(
std::move(texture_holder_), filter);
}
texture_holder_->Sync(mode);
}
void AcceleratedStaticBitmapImage::Transfer() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
EnsureMailbox(kVerifiedSyncToken, GL_NEAREST);
DETACH_FROM_THREAD(thread_checker_);
}
bool AcceleratedStaticBitmapImage::CurrentFrameKnownToBeOpaque() {
return texture_holder_->CurrentFrameKnownToBeOpaque();
}
} // namespace blink