Commit 4e4b52c1 authored by Khushal's avatar Khushal Committed by Commit Bot

canvas2d: Manage lifetime of SharedImage resource for StaticBitmapImage.

The StaticBitmapImage holds a reference to the SharedImage's mailbox
used by a canvas2d instance. Use a callback which wraps the
CanvasResource that owns this SharedImage to both ensure that the
SharedImage stays alive for the lifetime of the StaticBitmapImage and
the resource is recycled once all refs to the StaticBitmapImage have
been released.

R=kbr@chromium.org, piman@chromium.org

Bug: 948133
Change-Id: Ibc6f578fd8656a90b32a0267511d723f20cf745e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1610520
Commit-Queue: Khushal <khushalsagar@chromium.org>
Auto-Submit: Khushal <khushalsagar@chromium.org>
Reviewed-by: default avatarKenneth Russell <kbr@chromium.org>
Reviewed-by: default avatarAntoine Labour <piman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#660271}
parent d8291ab4
......@@ -54,6 +54,7 @@ include_rules = [
"+net/http/http_response_headers.h",
"+device",
"+gpu/GLES2",
"+gpu/command_buffer/common/sync_token.h",
"+mojo/public",
"+mozilla",
"+services/metrics/public/cpp/ukm_entry_builder.h",
......
......@@ -35,6 +35,7 @@
#include <vector>
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "gpu/command_buffer/common/sync_token.h"
#include "mojo/public/cpp/bindings/interface_ptr_info.h"
#include "mojo/public/cpp/bindings/interface_request.h"
#include "third_party/blink/public/common/messaging/message_port_channel.h"
......@@ -142,6 +143,12 @@ struct CrossThreadCopier<base::Time>
STATIC_ONLY(CrossThreadCopier);
};
template <>
struct CrossThreadCopier<gpu::SyncToken>
: public CrossThreadCopierPassThrough<gpu::SyncToken> {
STATIC_ONLY(CrossThreadCopier);
};
// nullptr_t can be passed through without any changes.
template <>
struct CrossThreadCopier<std::nullptr_t>
......
......@@ -4,6 +4,7 @@
#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"
......@@ -41,10 +42,11 @@ AcceleratedStaticBitmapImage::CreateFromWebGLContextImage(
base::WeakPtr<WebGraphicsContext3DProviderWrapper>&&
context_provider_wrapper,
IntSize mailbox_size,
MailboxType mailbox_type) {
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));
mailbox_size, mailbox_type, std::move(release_callback)));
}
AcceleratedStaticBitmapImage::AcceleratedStaticBitmapImage(
......@@ -65,9 +67,11 @@ AcceleratedStaticBitmapImage::AcceleratedStaticBitmapImage(
base::WeakPtr<WebGraphicsContext3DProviderWrapper>&&
context_provider_wrapper,
IntSize mailbox_size,
MailboxType mailbox_type)
MailboxType mailbox_type,
std::unique_ptr<viz::SingleReleaseCallback> release_callback)
: paint_image_content_id_(cc::PaintImage::GetNextContentId()),
mailbox_type_(mailbox_type) {
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);
......@@ -100,6 +104,11 @@ void DestroySkImageOnOriginalThread(
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.
......
......@@ -16,6 +16,10 @@
class GrContext;
namespace viz {
class SingleReleaseCallback;
} // namespace viz
namespace blink {
class WebGraphicsContext3DProviderWrapper;
class TextureHolder;
......@@ -32,10 +36,13 @@ class PLATFORM_EXPORT AcceleratedStaticBitmapImage final
base::WeakPtr<WebGraphicsContext3DProviderWrapper>);
// Can specify the GrContext that created the texture backing. Ideally all
// callers would use this option. The |mailbox| is a name for the texture
// backing, allowing other contexts to use the same backing. |mailbox_type|
// indicates whether |mailbox| is a SharedImage identifier or a deprecated
// mailbox (generated via ProduceTextureDirectCHROMIUM).
// callers would use this option.
// The |mailbox| is a name for the texture backing, allowing other contexts to
// use the same backing.
// |mailbox_type| indicates whether |mailbox| is a SharedImage identifier or a
// deprecated mailbox (generated via ProduceTextureDirectCHROMIUM).
// |release_callback| is an optional callback to be invoked when this image
// is destroyed. It can be invoked on any thread.
static scoped_refptr<AcceleratedStaticBitmapImage>
CreateFromWebGLContextImage(
const gpu::Mailbox&,
......@@ -43,7 +50,8 @@ class PLATFORM_EXPORT AcceleratedStaticBitmapImage final
unsigned texture_id,
base::WeakPtr<WebGraphicsContext3DProviderWrapper>&&,
IntSize mailbox_size,
MailboxType mailbox_type = MailboxType::kDeprecatedMailbox);
MailboxType mailbox_type = MailboxType::kDeprecatedMailbox,
std::unique_ptr<viz::SingleReleaseCallback> release_callback = nullptr);
bool CurrentFrameKnownToBeOpaque() override;
IntSize Size() const override;
......@@ -107,7 +115,8 @@ class PLATFORM_EXPORT AcceleratedStaticBitmapImage final
unsigned texture_id,
base::WeakPtr<WebGraphicsContext3DProviderWrapper>&&,
IntSize mailbox_size,
MailboxType mailbox_type);
MailboxType mailbox_type,
std::unique_ptr<viz::SingleReleaseCallback> release_callback);
void CreateImageFromMailboxIfNeeded();
void WaitSyncTokenIfNeeded();
......@@ -125,6 +134,7 @@ class PLATFORM_EXPORT AcceleratedStaticBitmapImage final
original_skia_image_context_provider_wrapper_;
const MailboxType mailbox_type_;
std::unique_ptr<viz::SingleReleaseCallback> release_callback_;
};
} // namespace blink
......
......@@ -16,12 +16,15 @@
#include "gpu/command_buffer/client/shared_image_interface.h"
#include "gpu/command_buffer/common/gpu_memory_buffer_support.h"
#include "gpu/command_buffer/common/shared_image_usage.h"
#include "gpu/command_buffer/common/sync_token.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/renderer/platform/cross_thread_functional.h"
#include "third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.h"
#include "third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.h"
#include "third_party/blink/renderer/platform/graphics/canvas_resource_provider.h"
#include "third_party/blink/renderer/platform/graphics/gpu/shared_gpu_context.h"
#include "third_party/blink/renderer/platform/graphics/static_bitmap_image.h"
#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
#include "third_party/skia/include/gpu/GrContext.h"
#include "ui/gfx/buffer_format_util.h"
......@@ -760,11 +763,41 @@ void CanvasResourceSharedImage::WillDraw() {
mailbox_needs_new_sync_token_ = true;
}
// static
void CanvasResourceSharedImage::OnBitmapImageDestroyed(
scoped_refptr<CanvasResourceSharedImage> resource,
scoped_refptr<base::SingleThreadTaskRunner> original_task_runner,
const gpu::SyncToken& sync_token,
bool is_lost) {
if (!original_task_runner->BelongsToCurrentThread()) {
PostCrossThreadTask(
*original_task_runner, FROM_HERE,
CrossThreadBind(&CanvasResourceSharedImage::OnBitmapImageDestroyed,
std::move(resource), std::move(original_task_runner),
sync_token, is_lost));
return;
}
auto weak_provider = resource->WeakProvider();
ReleaseFrameResources(std::move(weak_provider), std::move(resource),
sync_token, is_lost);
}
scoped_refptr<StaticBitmapImage> CanvasResourceSharedImage::Bitmap() {
// The |release_callback| keeps a ref on this resource to ensure the backing
// shared image is kept alive until the lifetime of the image.
// Note that the code in CanvasResourceProvider::RecycleResource also uses the
// ref-count on the resource as a proxy for a read lock to allow recycling the
// resource once all refs have been released.
auto release_callback = viz::SingleReleaseCallback::Create(base::BindOnce(
&OnBitmapImageDestroyed, scoped_refptr<CanvasResourceSharedImage>(this),
Thread::Current()->GetTaskRunner()));
scoped_refptr<StaticBitmapImage> image =
AcceleratedStaticBitmapImage::CreateFromWebGLContextImage(
shared_image_mailbox_, GetSyncToken(), 0, ContextProviderWrapper(),
Size());
Size(), AcceleratedStaticBitmapImage::MailboxType::kSharedImageId,
std::move(release_callback));
DCHECK(image);
return image;
}
......
......@@ -122,6 +122,7 @@ class PLATFORM_EXPORT CanvasResource
const CanvasColorParams& ColorParams() const { return color_params_; }
void OnDestroy();
CanvasResourceProvider* Provider() { return provider_.get(); }
base::WeakPtr<CanvasResourceProvider> WeakProvider() { return provider_; }
private:
// Sync token that was provided when resource was released
......@@ -340,6 +341,12 @@ class PLATFORM_EXPORT CanvasResourceSharedImage final : public CanvasResource {
void WillDraw();
private:
static void OnBitmapImageDestroyed(
scoped_refptr<CanvasResourceSharedImage> resource,
scoped_refptr<base::SingleThreadTaskRunner> original_task_runner,
const gpu::SyncToken& sync_token,
bool is_lost);
void TearDown() override;
base::WeakPtr<WebGraphicsContext3DProviderWrapper> ContextProviderWrapper()
const override;
......
......@@ -269,6 +269,41 @@ TEST_F(CanvasResourceProviderTest, CanvasResourceProviderSharedImage) {
EXPECT_NE(sync_token, resource_again->GetSyncToken());
}
TEST_F(CanvasResourceProviderTest,
CanvasResourceProviderSharedImageStaticBitmapImage) {
const IntSize kSize(10, 10);
const CanvasColorParams kColorParams(kSRGBCanvasColorSpace,
kRGBA8CanvasPixelFormat, kNonOpaque);
EnsureBufferFormatIsSupported(kColorParams.GetBufferFormat());
auto provider = CanvasResourceProvider::Create(
kSize, CanvasResourceProvider::kCreateSharedImageForTesting,
context_provider_wrapper_, 0 /* msaa_sample_count */, kColorParams,
CanvasResourceProvider::kAllowImageChromiumPresentationMode,
nullptr /* resource_dispatcher */, true /* is_origin_top_left */);
ASSERT_TRUE(provider->IsValid());
// Same resource returned until the canvas is updated.
auto image = provider->Snapshot();
ASSERT_TRUE(image);
auto new_image = provider->Snapshot();
EXPECT_EQ(image->GetMailbox(), new_image->GetMailbox());
EXPECT_EQ(provider->ProduceCanvasResource()->GetOrCreateGpuMailbox(
kOrderingBarrier),
image->GetMailbox());
// Resource updated after draw.
provider->Canvas()->clear(SK_ColorWHITE);
new_image = provider->Snapshot();
EXPECT_NE(new_image->GetMailbox(), image->GetMailbox());
// Resource recycled.
auto original_mailbox = image->GetMailbox();
image.reset();
provider->Canvas()->clear(SK_ColorBLACK);
EXPECT_EQ(original_mailbox, provider->Snapshot()->GetMailbox());
}
TEST_F(CanvasResourceProviderTest, CanvasResourceProviderBitmap) {
const IntSize kSize(10, 10);
const CanvasColorParams kColorParams(kSRGBCanvasColorSpace,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment