Commit 10de2b1d authored by Justin Novosad's avatar Justin Novosad Committed by Commit Bot

Fix GPU Mailbox leak in CanvasResource_Skia

This change adds a call to ProduceTextureDirectCHROIMIUM to
disassociate a mailbox from its texture in case the texture
gets recycled by skia, in which case the mailbox name would be
leaked.

BUG=789742

Cq-Include-Trybots: master.tryserver.chromium.linux:linux_layout_tests_slimming_paint_v2
Change-Id: Ic07fc9897a2fa9e42bc5b1202e044c4171ca9f9a
Reviewed-on: https://chromium-review.googlesource.com/801496Reviewed-by: default avatarOlivia Lai <xlai@chromium.org>
Commit-Queue: Justin Novosad <junov@chromium.org>
Cr-Commit-Position: refs/heads/master@{#520720}
parent e36bfd5b
...@@ -1806,6 +1806,7 @@ jumbo_source_set("blink_platform_unittests_sources") { ...@@ -1806,6 +1806,7 @@ jumbo_source_set("blink_platform_unittests_sources") {
"geometry/LayoutSizeTest.cpp", "geometry/LayoutSizeTest.cpp",
"geometry/RegionTest.cpp", "geometry/RegionTest.cpp",
"graphics/BitmapImageTest.cpp", "graphics/BitmapImageTest.cpp",
"graphics/CanvasResourceTest.cpp",
"graphics/CompositorElementIdTest.cpp", "graphics/CompositorElementIdTest.cpp",
"graphics/ContiguousContainerTest.cpp", "graphics/ContiguousContainerTest.cpp",
"graphics/DecodingImageGeneratorTest.cpp", "graphics/DecodingImageGeneratorTest.cpp",
......
...@@ -40,6 +40,10 @@ const gpu::Mailbox& CanvasResource::GpuMailbox() { ...@@ -40,6 +40,10 @@ const gpu::Mailbox& CanvasResource::GpuMailbox() {
return gpu_mailbox_; return gpu_mailbox_;
} }
bool CanvasResource::HasGpuMailbox() const {
return !gpu_mailbox_.IsZero();
}
void CanvasResource::SetSyncTokenForRelease(const gpu::SyncToken& token) { void CanvasResource::SetSyncTokenForRelease(const gpu::SyncToken& token) {
sync_token_for_release_ = token; sync_token_for_release_ = token;
} }
...@@ -82,6 +86,13 @@ bool CanvasResource_Skia::IsValid() const { ...@@ -82,6 +86,13 @@ bool CanvasResource_Skia::IsValid() const {
void CanvasResource_Skia::Abandon() { void CanvasResource_Skia::Abandon() {
WaitSyncTokenBeforeRelease(); WaitSyncTokenBeforeRelease();
auto gl = ContextGL();
if (gl && HasGpuMailbox()) {
DCHECK(image_->isTextureBacked());
// To avoid leaking Mailbox records, we must disassociate the mailbox
// before image_ goes out of scope because skia might recycle the texture.
gl->ProduceTextureDirectCHROMIUM(0, GL_TEXTURE_2D, GpuMailbox().name);
}
image_ = nullptr; image_ = nullptr;
context_provider_wrapper_ = nullptr; context_provider_wrapper_ = nullptr;
} }
...@@ -134,6 +145,10 @@ CanvasResource_GpuMemoryBuffer::CanvasResource_GpuMemoryBuffer( ...@@ -134,6 +145,10 @@ CanvasResource_GpuMemoryBuffer::CanvasResource_GpuMemoryBuffer(
gr->resetContext(kTextureBinding_GrGLBackendState); gr->resetContext(kTextureBinding_GrGLBackendState);
} }
CanvasResource_GpuMemoryBuffer::~CanvasResource_GpuMemoryBuffer() {
Abandon();
}
scoped_refptr<CanvasResource_GpuMemoryBuffer> scoped_refptr<CanvasResource_GpuMemoryBuffer>
CanvasResource_GpuMemoryBuffer::Create( CanvasResource_GpuMemoryBuffer::Create(
const IntSize& size, const IntSize& size,
......
...@@ -32,6 +32,7 @@ class PLATFORM_EXPORT CanvasResource : public WTF::RefCounted<CanvasResource> { ...@@ -32,6 +32,7 @@ class PLATFORM_EXPORT CanvasResource : public WTF::RefCounted<CanvasResource> {
virtual GLuint TextureId() const = 0; virtual GLuint TextureId() const = 0;
gpu::gles2::GLES2Interface* ContextGL() const; gpu::gles2::GLES2Interface* ContextGL() const;
const gpu::Mailbox& GpuMailbox(); const gpu::Mailbox& GpuMailbox();
bool HasGpuMailbox() const;
void SetSyncTokenForRelease(const gpu::SyncToken&); void SetSyncTokenForRelease(const gpu::SyncToken&);
void WaitSyncTokenBeforeRelease(); void WaitSyncTokenBeforeRelease();
...@@ -74,7 +75,7 @@ class PLATFORM_EXPORT CanvasResource_GpuMemoryBuffer final ...@@ -74,7 +75,7 @@ class PLATFORM_EXPORT CanvasResource_GpuMemoryBuffer final
const IntSize&, const IntSize&,
const CanvasColorParams&, const CanvasColorParams&,
WeakPtr<WebGraphicsContext3DProviderWrapper>); WeakPtr<WebGraphicsContext3DProviderWrapper>);
virtual ~CanvasResource_GpuMemoryBuffer() { Abandon(); } virtual ~CanvasResource_GpuMemoryBuffer();
bool IsRecycleable() const final { return IsValid(); } bool IsRecycleable() const final { return IsValid(); }
bool IsValid() const { return context_provider_wrapper_ && image_id_; } bool IsValid() const { return context_provider_wrapper_ && image_id_; }
void Abandon() final; void Abandon() final;
......
// 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/CanvasResource.h"
#include "platform/graphics/gpu/SharedGpuContext.h"
#include "platform/graphics/test/FakeGLES2Interface.h"
#include "platform/graphics/test/FakeWebGraphicsContext3DProvider.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkSurface.h"
using ::testing::_;
using ::testing::Pointee;
using ::testing::SetArrayArgument;
using ::testing::Test;
namespace blink {
class MockGLES2InterfaceWithMailboxSupport : public FakeGLES2Interface {
public:
MOCK_METHOD3(ProduceTextureDirectCHROMIUM,
void(GLuint, GLenum, const GLbyte*));
MOCK_METHOD1(GenMailboxCHROMIUM, void(GLbyte*));
};
class CanvasResourceTest : public Test {
public:
void SetUp() override {
// Install our mock GL context so that it gets served by SharedGpuContext.
auto factory = [](FakeGLES2Interface* gl, bool* gpu_compositing_disabled)
-> std::unique_ptr<WebGraphicsContext3DProvider> {
*gpu_compositing_disabled = false;
return std::make_unique<FakeWebGraphicsContext3DProvider>(gl);
};
SharedGpuContext::SetContextProviderFactoryForTesting(
WTF::Bind(factory, WTF::Unretained(&gl_)));
context_provider_wrapper_ = SharedGpuContext::ContextProviderWrapper();
}
void TearDown() override { SharedGpuContext::ResetForTesting(); }
GrContext* GetGrContext() {
return context_provider_wrapper_->ContextProvider()->GetGrContext();
}
protected:
MockGLES2InterfaceWithMailboxSupport gl_;
WeakPtr<WebGraphicsContext3DProviderWrapper> context_provider_wrapper_;
};
TEST_F(CanvasResourceTest, SkiaResourceNoMailboxLeak) {
SkImageInfo image_info =
SkImageInfo::MakeN32(10, 10, kPremul_SkAlphaType, nullptr);
sk_sp<SkSurface> surface =
SkSurface::MakeRenderTarget(GetGrContext(), SkBudgeted::kYes, image_info);
::testing::Mock::VerifyAndClearExpectations(&gl_);
EXPECT_TRUE(!!context_provider_wrapper_);
scoped_refptr<CanvasResource> resource = CanvasResource_Skia::Create(
surface->makeImageSnapshot(), context_provider_wrapper_);
::testing::Mock::VerifyAndClearExpectations(&gl_);
gpu::Mailbox test_mailbox;
test_mailbox.name[0] = 1;
EXPECT_CALL(gl_, GenMailboxCHROMIUM(_))
.WillOnce(SetArrayArgument<0>(
test_mailbox.name, test_mailbox.name + GL_MAILBOX_SIZE_CHROMIUM));
resource->GpuMailbox();
::testing::Mock::VerifyAndClearExpectations(&gl_);
// No expected call to DeleteTextures becaus skia recycles
EXPECT_CALL(gl_, ProduceTextureDirectCHROMIUM(0, GL_TEXTURE_2D,
Pointee(test_mailbox.name[0])))
.Times(1);
resource = nullptr;
::testing::Mock::VerifyAndClearExpectations(&gl_);
}
} // namespace blink
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