#ifdef UNSAFE_BUFFERS_BUILD
#pragma allow_unsafe_libc_calls
#endif
#include "cc/layers/texture_layer.h"
#include <stddef.h>
#include <stdint.h>
#include <algorithm>
#include <memory>
#include <string>
#include <utility>
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/location.h"
#include "base/memory/ptr_util.h"
#include "base/memory/raw_ptr.h"
#include "base/run_loop.h"
#include "base/synchronization/lock.h"
#include "base/synchronization/waitable_event.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/single_thread_task_runner.h"
#include "base/threading/thread.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "cc/animation/animation_host.h"
#include "cc/layers/solid_color_layer.h"
#include "cc/layers/texture_layer_client.h"
#include "cc/layers/texture_layer_impl.h"
#include "cc/test/fake_impl_task_runner_provider.h"
#include "cc/test/fake_layer_tree_frame_sink.h"
#include "cc/test/fake_layer_tree_host_client.h"
#include "cc/test/fake_layer_tree_host_impl.h"
#include "cc/test/layer_test_common.h"
#include "cc/test/layer_tree_test.h"
#include "cc/test/stub_layer_tree_host_single_thread_client.h"
#include "cc/test/test_layer_tree_frame_sink.h"
#include "cc/test/test_task_graph_runner.h"
#include "cc/trees/layer_tree_host.h"
#include "cc/trees/layer_tree_impl.h"
#include "cc/trees/single_thread_proxy.h"
#include "components/viz/common/gpu/raster_context_provider.h"
#include "components/viz/common/quads/texture_draw_quad.h"
#include "components/viz/common/resources/returned_resource.h"
#include "components/viz/common/resources/transferable_resource.h"
#include "components/viz/common/surfaces/parent_local_surface_id_allocator.h"
#include "components/viz/service/display/software_output_device.h"
#include "components/viz/test/fake_output_surface.h"
#include "gpu/GLES2/gl2extchromium.h"
#include "gpu/command_buffer/client/shared_image_interface.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using ::testing::_;
using ::testing::AnyNumber;
using ::testing::AtLeast;
using ::testing::InvokeWithoutArgs;
using ::testing::Mock;
#define EXPECT_SET_NEEDS_COMMIT(expect, code_to_test) \
do { \
EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times((expect)); \
code_to_test; \
Mock::VerifyAndClearExpectations(layer_tree_host_.get()); \
} while (false)
namespace cc {
namespace {
MATCHER_P(SameSyncToken, other, "") {
gpu::SyncToken a = arg;
gpu::SyncToken b = other;
a.SetVerifyFlush();
b.SetVerifyFlush();
return a == b;
}
gpu::SyncToken GenSyncToken() {
static int next_release = 1;
return gpu::SyncToken(gpu::CommandBufferNamespace::GPU_IO,
gpu::CommandBufferId::FromUnsafeValue(0x234),
next_release++);
}
viz::TransferableResource MakeFakeResource(
const viz::TransferableResource::MetadataOverride& override = {}) {
return viz::TransferableResource::Make(
gpu::ClientSharedImage::CreateForTesting(),
viz::TransferableResource::ResourceSource::kTest, GenSyncToken(),
override);
}
viz::TransferableResource MakeFakeSoftwareResource() {
auto sync_token = GenSyncToken();
sync_token.SetVerifyFlush();
return viz::TransferableResource::Make(
gpu::ClientSharedImage::CreateSoftwareForTesting(),
viz::TransferableResource::ResourceSource::kTest, sync_token);
}
class MockLayerTreeHost : public LayerTreeHost {
public:
static std::unique_ptr<MockLayerTreeHost> Create(
FakeLayerTreeHostClient* client,
TaskGraphRunner* task_graph_runner,
MutatorHost* mutator_host) {
LayerTreeHost::InitParams params;
params.client = client;
params.task_graph_runner = task_graph_runner;
params.mutator_host = mutator_host;
LayerTreeSettings settings;
params.settings = &settings;
return base::WrapUnique(new MockLayerTreeHost(std::move(params)));
}
MOCK_METHOD0(SetNeedsCommit, void());
MOCK_METHOD0(StartRateLimiter, void());
MOCK_METHOD0(StopRateLimiter, void());
private:
explicit MockLayerTreeHost(LayerTreeHost::InitParams params)
: LayerTreeHost(std::move(params), CompositorMode::SINGLE_THREADED) {
InitializeSingleThreaded(&single_thread_client_,
base::SingleThreadTaskRunner::GetCurrentDefault());
}
StubLayerTreeHostSingleThreadClient single_thread_client_;
};
class MockReleaseCallback {
public:
MOCK_METHOD2(Release,
void(const gpu::SyncToken& sync_token, bool lost_resource));
};
struct CommonResourceObjects {
explicit CommonResourceObjects(bool software) {
if (software) {
resource = MakeFakeSoftwareResource();
} else {
resource = MakeFakeResource();
}
creation_sync_token = resource.sync_token();
release_callback = base::BindRepeating(&MockReleaseCallback::Release,
base::Unretained(&mock_callback));
}
CommonResourceObjects& ExpectReleaseWithSyncToken(
const gpu::SyncToken& sync_token,
bool lost) {
EXPECT_CALL(mock_callback, Release(sync_token, lost)).Times(1);
return *this;
}
CommonResourceObjects& ExpectRelease() {
EXPECT_CALL(mock_callback,
Release(SameSyncToken(creation_sync_token), false))
.Times(1);
return *this;
}
CommonResourceObjects& ExpectNoRelease() {
EXPECT_CALL(mock_callback, Release(_, _)).Times(0);
return *this;
}
void Verify() { Mock::VerifyAndClearExpectations(&mock_callback); }
using RepeatingReleaseCallback =
base::RepeatingCallback<void(const gpu::SyncToken& sync_token,
bool is_lost)>;
RepeatingReleaseCallback release_callback;
viz::TransferableResource resource;
gpu::SyncToken creation_sync_token;
MockReleaseCallback mock_callback;
};
class TextureLayerTest : public testing::Test {
public:
TextureLayerTest()
: layer_tree_frame_sink_(FakeLayerTreeFrameSink::Create3d()),
host_impl_(&task_runner_provider_, &task_graph_runner_) {}
protected:
void SetUp() override {
animation_host_ = AnimationHost::CreateForTesting(ThreadInstance::kMain);
layer_tree_host_ = MockLayerTreeHost::Create(
&fake_client_, &task_graph_runner_, animation_host_.get());
EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AnyNumber());
layer_tree_host_->SetViewportRectAndScale(gfx::Rect(10, 10), 1.f,
viz::LocalSurfaceId());
Mock::VerifyAndClearExpectations(layer_tree_host_.get());
}
void TearDown() override {
Mock::VerifyAndClearExpectations(layer_tree_host_.get());
EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AnyNumber());
animation_host_->SetMutatorHostClient(nullptr);
layer_tree_host_->SetRootLayer(nullptr);
layer_tree_host_ = nullptr;
animation_host_ = nullptr;
}
std::unique_ptr<MockLayerTreeHost> layer_tree_host_;
std::unique_ptr<AnimationHost> animation_host_;
FakeImplTaskRunnerProvider task_runner_provider_;
FakeLayerTreeHostClient fake_client_;
TestTaskGraphRunner task_graph_runner_;
std::unique_ptr<LayerTreeFrameSink> layer_tree_frame_sink_;
FakeLayerTreeHostImpl host_impl_;
CommonResourceObjects test_resource1_{false};
CommonResourceObjects test_resource2_{false};
CommonResourceObjects test_resource_sw_{true};
};
TEST_F(TextureLayerTest, CheckPropertyChangeCausesCorrectBehavior) {
scoped_refptr<TextureLayer> test_layer = TextureLayer::Create(nullptr);
EXPECT_SET_NEEDS_COMMIT(1, layer_tree_host_->SetRootLayer(test_layer));
EXPECT_SET_NEEDS_COMMIT(
1, test_layer->SetFilterQuality(PaintFlags::FilterQuality::kNone));
EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetDynamicRangeLimit(
PaintFlags::DynamicRangeLimitMixture(
PaintFlags::DynamicRangeLimit::kStandard)
));
EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetUV(gfx::PointF(0.25f, 0.25f),
gfx::PointF(0.75f, 0.75f)));
EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetBlendBackgroundColor(true));
}
class RunOnCommitLayerTreeHostClient : public FakeLayerTreeHostClient {
public:
void set_run_on_commit_and_draw(base::OnceClosure c) {
run_on_commit_and_draw_ = std::move(c);
}
void DidCommitAndDrawFrame(int source_frame_number) override {
if (run_on_commit_and_draw_)
std::move(run_on_commit_and_draw_).Run();
}
private:
base::OnceClosure run_on_commit_and_draw_;
};
TEST_F(TextureLayerTest, ShutdownWithResource) {
for (int i = 0; i < 2; ++i) {
bool gpu = i == 0;
SCOPED_TRACE(gpu);
StubLayerTreeHostSingleThreadClient single_thread_client;
RunOnCommitLayerTreeHostClient client;
LayerTreeHost::InitParams params;
params.client = &client;
params.task_graph_runner = &task_graph_runner_;
params.mutator_host = animation_host_.get();
LayerTreeSettings settings;
params.settings = &settings;
params.main_task_runner = base::SingleThreadTaskRunner::GetCurrentDefault();
auto host = LayerTreeHost::CreateSingleThreaded(&single_thread_client,
std::move(params));
client.SetLayerTreeHost(host.get());
client.SetUseSoftwareCompositing(!gpu);
scoped_refptr<TextureLayer> layer = TextureLayer::Create(nullptr);
layer->SetIsDrawable(true);
layer->SetBounds(gfx::Size(10, 10));
auto& test_resource = gpu ? test_resource1_ : test_resource_sw_;
layer->SetTransferableResource(test_resource.resource,
test_resource.release_callback);
viz::ParentLocalSurfaceIdAllocator allocator;
allocator.GenerateId();
host->SetViewportRectAndScale(gfx::Rect(10, 10), 1.f,
allocator.GetCurrentLocalSurfaceId());
host->SetVisible(true);
host->SetRootLayer(layer);
{
base::RunLoop loop;
client.set_run_on_commit_and_draw(loop.QuitClosure());
loop.Run();
}
client.SetLayerTreeHost(nullptr);
host = nullptr;
test_resource.ExpectRelease();
{
base::RunLoop loop;
loop.RunUntilIdle();
}
}
}
class TestMailboxHolder : public TextureLayer::TransferableResourceHolder {
public:
using TextureLayer::TransferableResourceHolder::Create;
protected:
~TestMailboxHolder() override = default;
};
class TextureLayerWithResourceTest : public TextureLayerTest {
protected:
void TearDown() override {
test_resource1_.Verify();
test_resource1_.ExpectRelease();
TextureLayerTest::TearDown();
}
};
TEST_F(TextureLayerWithResourceTest, ReplaceMailboxOnMainThreadBeforeCommit) {
scoped_refptr<TextureLayer> test_layer = TextureLayer::Create(nullptr);
ASSERT_TRUE(test_layer.get());
EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AnyNumber());
layer_tree_host_->SetRootLayer(test_layer);
Mock::VerifyAndClearExpectations(layer_tree_host_.get());
EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AtLeast(1));
test_layer->SetTransferableResource(test_resource1_.resource,
test_resource1_.release_callback);
Mock::VerifyAndClearExpectations(layer_tree_host_.get());
EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AtLeast(1));
test_resource1_.ExpectRelease();
test_layer->SetTransferableResource(test_resource2_.resource,
test_resource2_.release_callback);
Mock::VerifyAndClearExpectations(layer_tree_host_.get());
test_resource1_.Verify();
EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AtLeast(1));
test_resource2_.ExpectRelease();
test_layer->ClearTexture();
Mock::VerifyAndClearExpectations(layer_tree_host_.get());
test_resource2_.Verify();
EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AtLeast(1));
test_layer->SetTransferableResource(test_resource1_.resource,
test_resource1_.release_callback);
Mock::VerifyAndClearExpectations(layer_tree_host_.get());
EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AtLeast(1));
test_resource1_.ExpectRelease();
test_layer->ClearTexture();
Mock::VerifyAndClearExpectations(layer_tree_host_.get());
test_resource1_.Verify();
EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AtLeast(1));
test_layer->SetTransferableResource(test_resource1_.resource,
test_resource1_.release_callback);
}
TEST_F(TextureLayerWithResourceTest, AffectedByHdr) {
scoped_refptr<TextureLayer> test_layer = TextureLayer::Create(nullptr);
ASSERT_TRUE(test_layer.get());
EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AnyNumber());
layer_tree_host_->SetRootLayer(test_layer);
Mock::VerifyAndClearExpectations(layer_tree_host_.get());
EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AtLeast(1));
test_resource1_.resource =
MakeFakeResource({.color_space = gfx::ColorSpace::CreateSRGB()});
test_resource1_.creation_sync_token = test_resource1_.resource.sync_token();
test_layer->SetTransferableResource(test_resource1_.resource,
test_resource1_.release_callback);
Mock::VerifyAndClearExpectations(layer_tree_host_.get());
EXPECT_FALSE(test_layer->RequiresSetNeedsDisplayOnHdrHeadroomChange());
EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AtLeast(1));
test_resource1_.ExpectRelease();
test_resource2_.resource =
MakeFakeResource({.color_space = gfx::ColorSpace::CreateHDR10()});
test_resource2_.creation_sync_token = test_resource2_.resource.sync_token();
test_layer->SetTransferableResource(test_resource2_.resource,
test_resource2_.release_callback);
Mock::VerifyAndClearExpectations(layer_tree_host_.get());
EXPECT_TRUE(test_layer->RequiresSetNeedsDisplayOnHdrHeadroomChange());
test_resource2_.ExpectRelease();
EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AtLeast(1));
test_resource1_.resource.hdr_metadata.extended_range.emplace(5.f, 5.f);
test_layer->SetTransferableResource(test_resource1_.resource,
test_resource1_.release_callback);
Mock::VerifyAndClearExpectations(layer_tree_host_.get());
EXPECT_TRUE(test_layer->RequiresSetNeedsDisplayOnHdrHeadroomChange());
}
class TextureLayerMailboxHolderTest : public TextureLayerTest {
public:
TextureLayerMailboxHolderTest() : main_thread_("MAIN") {
main_thread_.Start();
sync_token1_ = GenSyncToken();
sync_token2_ = GenSyncToken();
}
void Wait(const base::Thread& thread) {
base::WaitableEvent event(base::WaitableEvent::ResetPolicy::AUTOMATIC,
base::WaitableEvent::InitialState::NOT_SIGNALED);
thread.task_runner()->PostTask(
FROM_HERE,
base::BindOnce(&base::WaitableEvent::Signal, base::Unretained(&event)));
event.Wait();
}
void CreateMainRef() {
resource_holder_ = TestMailboxHolder::Create(
test_resource1_.resource, test_resource1_.release_callback);
}
void ReleaseMainRef() { resource_holder_ = nullptr; }
void CreateImplRef(
viz::ReleaseCallback* impl_ref,
scoped_refptr<base::SequencedTaskRunner> main_thread_task_runner) {
*impl_ref =
base::BindOnce(&TextureLayer::TransferableResourceHolder::Return,
resource_holder_, main_thread_task_runner);
}
protected:
scoped_refptr<TextureLayer::TransferableResourceHolder> resource_holder_;
base::Thread main_thread_;
gpu::SyncToken sync_token1_;
gpu::SyncToken sync_token2_;
};
TEST_F(TextureLayerMailboxHolderTest, TwoCompositors_BothReleaseThenMain) {
scoped_refptr<TextureLayer> test_layer = TextureLayer::Create(nullptr);
ASSERT_TRUE(test_layer.get());
main_thread_.task_runner()->PostTask(
FROM_HERE, base::BindOnce(&TextureLayerMailboxHolderTest::CreateMainRef,
base::Unretained(this)));
Wait(main_thread_);
viz::ReleaseCallback compositor1;
main_thread_.task_runner()->PostTask(
FROM_HERE, base::BindOnce(&TextureLayerMailboxHolderTest::CreateImplRef,
base::Unretained(this), &compositor1,
main_thread_.task_runner()));
viz::ReleaseCallback compositor2;
main_thread_.task_runner()->PostTask(
FROM_HERE, base::BindOnce(&TextureLayerMailboxHolderTest::CreateImplRef,
base::Unretained(this), &compositor2,
main_thread_.task_runner()));
Wait(main_thread_);
test_resource1_.Verify();
std::move(compositor1).Run(sync_token1_, false);
std::move(compositor2).Run(sync_token2_, false);
Wait(main_thread_);
test_resource1_.ExpectNoRelease().Verify();
test_resource1_.ExpectReleaseWithSyncToken(sync_token2_, false);
main_thread_.task_runner()->PostTask(
FROM_HERE, base::BindOnce(&TextureLayerMailboxHolderTest::ReleaseMainRef,
base::Unretained(this)));
Wait(main_thread_);
test_resource1_.Verify();
}
TEST_F(TextureLayerMailboxHolderTest, TwoCompositors_MainReleaseBetween) {
scoped_refptr<TextureLayer> test_layer = TextureLayer::Create(nullptr);
ASSERT_TRUE(test_layer.get());
main_thread_.task_runner()->PostTask(
FROM_HERE, base::BindOnce(&TextureLayerMailboxHolderTest::CreateMainRef,
base::Unretained(this)));
Wait(main_thread_);
viz::ReleaseCallback compositor1;
main_thread_.task_runner()->PostTask(
FROM_HERE, base::BindOnce(&TextureLayerMailboxHolderTest::CreateImplRef,
base::Unretained(this), &compositor1,
main_thread_.task_runner()));
viz::ReleaseCallback compositor2;
main_thread_.task_runner()->PostTask(
FROM_HERE, base::BindOnce(&TextureLayerMailboxHolderTest::CreateImplRef,
base::Unretained(this), &compositor2,
main_thread_.task_runner()));
Wait(main_thread_);
test_resource1_.ExpectNoRelease().Verify();
std::move(compositor1).Run(sync_token1_, false);
main_thread_.task_runner()->PostTask(
FROM_HERE, base::BindOnce(&TextureLayerMailboxHolderTest::ReleaseMainRef,
base::Unretained(this)));
Wait(main_thread_);
test_resource1_.ExpectNoRelease().Verify();
test_resource1_.ExpectReleaseWithSyncToken(sync_token2_, true);
std::move(compositor2).Run(sync_token2_, true);
Wait(main_thread_);
test_resource1_.Verify();
}
TEST_F(TextureLayerMailboxHolderTest, TwoCompositors_MainReleasedFirst) {
scoped_refptr<TextureLayer> test_layer = TextureLayer::Create(nullptr);
ASSERT_TRUE(test_layer.get());
main_thread_.task_runner()->PostTask(
FROM_HERE, base::BindOnce(&TextureLayerMailboxHolderTest::CreateMainRef,
base::Unretained(this)));
Wait(main_thread_);
viz::ReleaseCallback compositor1;
main_thread_.task_runner()->PostTask(
FROM_HERE, base::BindOnce(&TextureLayerMailboxHolderTest::CreateImplRef,
base::Unretained(this), &compositor1,
main_thread_.task_runner()));
viz::ReleaseCallback compositor2;
main_thread_.task_runner()->PostTask(
FROM_HERE, base::BindOnce(&TextureLayerMailboxHolderTest::CreateImplRef,
base::Unretained(this), &compositor2,
main_thread_.task_runner()));
Wait(main_thread_);
test_resource1_.ExpectNoRelease().Verify();
main_thread_.task_runner()->PostTask(
FROM_HERE, base::BindOnce(&TextureLayerMailboxHolderTest::ReleaseMainRef,
base::Unretained(this)));
std::move(compositor2).Run(sync_token2_, false);
Wait(main_thread_);
test_resource1_.ExpectNoRelease().Verify();
test_resource1_.ExpectReleaseWithSyncToken(sync_token1_, true);
std::move(compositor1).Run(sync_token1_, true);
Wait(main_thread_);
test_resource1_.Verify();
}
class TextureLayerImplWithMailboxThreadedCallback : public LayerTreeTest {
public:
std::unique_ptr<TestLayerTreeFrameSink> CreateLayerTreeFrameSink(
const viz::RendererSettings& renderer_settings,
double refresh_rate,
scoped_refptr<viz::RasterContextProvider> compositor_context_provider,
scoped_refptr<viz::RasterContextProvider> worker_context_provider)
override {
constexpr bool disable_display_vsync = false;
bool synchronous_composite =
!HasImplThread() &&
!layer_tree_host()->GetSettings().single_thread_proxy_scheduler;
return std::make_unique<TestLayerTreeFrameSink>(
compositor_context_provider, std::move(worker_context_provider),
nullptr, renderer_settings, &debug_settings_,
task_runner_provider(), synchronous_composite, disable_display_vsync,
refresh_rate);
}
void AdvanceTestCase() {
++test_case_;
switch (test_case_) {
case 1:
SetNewFakeResource();
EXPECT_EQ(1, callback_count_);
PostSetNeedsCommitToMainThread();
pending_callback_ = false;
break;
case 2:
SetNewFakeResource();
EXPECT_EQ(1, callback_count_);
pending_callback_ = true;
break;
case 3:
EXPECT_EQ(2, callback_count_);
layer_->SetBounds(gfx::Size());
SetNewFakeResource();
break;
case 4:
EXPECT_EQ(3, callback_count_);
layer_->ClearTexture();
break;
case 5:
EXPECT_EQ(4, callback_count_);
SetNewFakeResource();
pending_callback_ = false;
break;
case 6:
EXPECT_EQ(4, callback_count_);
layer_->RemoveFromParent();
break;
case 7:
EXPECT_EQ(4, callback_count_);
pending_callback_ = true;
layer_->ClearTexture();
frame_number_ = layer_tree_host()->SourceFrameNumber();
break;
case 8:
EXPECT_EQ(frame_number_, layer_tree_host()->SourceFrameNumber());
EXPECT_EQ(5, callback_count_);
EndTest();
break;
default:
NOTREACHED();
}
}
void ReleaseCallback(const gpu::SyncToken& sync_token, bool lost_resource) {
EXPECT_EQ(true, main_thread_.CalledOnValidThread());
EXPECT_FALSE(lost_resource);
++callback_count_;
if (pending_callback_) {
layer_tree_host()
->GetTaskRunnerProvider()
->MainThreadTaskRunner()
->PostTask(
FROM_HERE,
base::BindOnce(
&TextureLayerImplWithMailboxThreadedCallback::AdvanceTestCase,
base::Unretained(this)));
}
}
void SetNewFakeResource() {
EXPECT_EQ(true, main_thread_.CalledOnValidThread());
viz::ReleaseCallback callback = base::BindOnce(
&TextureLayerImplWithMailboxThreadedCallback::ReleaseCallback,
base::Unretained(this));
auto resource = MakeFakeResource();
layer_->SetTransferableResource(resource, std::move(callback));
layer_->SetNeedsDisplay();
}
void BeginTest() override {
EXPECT_EQ(true, main_thread_.CalledOnValidThread());
gfx::Size bounds(100, 100);
root_ = Layer::Create();
root_->SetBounds(bounds);
layer_ = TextureLayer::Create(nullptr);
layer_->SetIsDrawable(true);
layer_->SetBounds(bounds);
root_->AddChild(layer_);
layer_tree_host()->SetRootLayer(root_);
layer_tree_host()->SetViewportRectAndScale(gfx::Rect(bounds), 1.f,
viz::LocalSurfaceId());
SetNewFakeResource();
EXPECT_EQ(0, callback_count_);
AdvanceTestCase();
}
void DidCommit() override {
if (!pending_callback_)
AdvanceTestCase();
}
private:
base::ThreadChecker main_thread_;
int callback_count_ = 0;
int test_case_ = 0;
int frame_number_ = 0;
bool pending_callback_ = false;
scoped_refptr<Layer> root_;
scoped_refptr<TextureLayer> layer_;
};
SINGLE_AND_MULTI_THREAD_TEST_F(TextureLayerImplWithMailboxThreadedCallback);
class TextureLayerImplWithResourceTest : public TextureLayerTest {
protected:
void SetUp() override {
TextureLayerTest::SetUp();
layer_tree_host_ = MockLayerTreeHost::Create(
&fake_client_, &task_graph_runner_, animation_host_.get());
host_impl_.SetVisible(true);
EXPECT_TRUE(host_impl_.InitializeFrameSink(layer_tree_frame_sink_.get()));
}
std::unique_ptr<TextureLayerImpl> CreateTextureLayer() {
auto layer = TextureLayerImpl::Create(host_impl_.active_tree(), 1);
layer->SetVisibleLayerRectForTesting(gfx::Rect(100, 100));
return layer;
}
bool WillDraw(TextureLayerImpl* layer, DrawMode mode) {
bool will_draw =
layer->WillDraw(mode, host_impl_.active_tree()->resource_provider());
if (will_draw)
layer->DidDraw(host_impl_.active_tree()->resource_provider());
return will_draw;
}
FakeLayerTreeHostClient fake_client_;
};
TEST_F(TextureLayerImplWithResourceTest, TestWillDraw) {
{
std::unique_ptr<TextureLayerImpl> impl_layer = CreateTextureLayer();
impl_layer->SetTransferableResource(test_resource1_.resource,
test_resource1_.release_callback);
EXPECT_TRUE(WillDraw(impl_layer.get(), DRAW_MODE_HARDWARE));
}
{
std::unique_ptr<TextureLayerImpl> impl_layer =
TextureLayerImpl::Create(host_impl_.active_tree(), 1);
impl_layer->SetTransferableResource(viz::TransferableResource(),
viz::ReleaseCallback());
EXPECT_FALSE(WillDraw(impl_layer.get(), DRAW_MODE_HARDWARE));
}
{
std::unique_ptr<TextureLayerImpl> impl_layer = CreateTextureLayer();
impl_layer->SetTransferableResource(test_resource1_.resource,
test_resource1_.release_callback);
EXPECT_FALSE(WillDraw(impl_layer.get(), DRAW_MODE_SOFTWARE));
}
{
std::unique_ptr<TextureLayerImpl> impl_layer = CreateTextureLayer();
impl_layer->SetTransferableResource(viz::TransferableResource(),
viz::ReleaseCallback());
EXPECT_FALSE(WillDraw(impl_layer.get(), DRAW_MODE_SOFTWARE));
}
{
std::unique_ptr<TextureLayerImpl> impl_layer = CreateTextureLayer();
impl_layer->SetTransferableResource(test_resource_sw_.resource,
test_resource_sw_.release_callback);
EXPECT_TRUE(WillDraw(impl_layer.get(), DRAW_MODE_SOFTWARE));
}
{
std::unique_ptr<TextureLayerImpl> impl_layer = CreateTextureLayer();
impl_layer->SetTransferableResource(test_resource1_.resource,
test_resource1_.release_callback);
EXPECT_FALSE(WillDraw(impl_layer.get(), DRAW_MODE_RESOURCELESS_SOFTWARE));
}
}
TEST_F(TextureLayerImplWithResourceTest, TestImplLayerCallbacks) {
host_impl_.CreatePendingTree();
std::unique_ptr<TextureLayerImpl> pending_layer;
pending_layer = TextureLayerImpl::Create(host_impl_.pending_tree(), 1);
ASSERT_TRUE(pending_layer);
std::unique_ptr<LayerImpl> active_layer(
pending_layer->CreateLayerImpl(host_impl_.active_tree()));
ASSERT_TRUE(active_layer);
pending_layer->SetTransferableResource(test_resource1_.resource,
test_resource1_.release_callback);
test_resource1_.ExpectRelease();
pending_layer->SetTransferableResource(test_resource2_.resource,
test_resource2_.release_callback);
test_resource1_.Verify();
pending_layer->PushPropertiesTo(active_layer.get());
active_layer->DidBecomeActive();
test_resource1_.ExpectNoRelease();
pending_layer->SetTransferableResource(test_resource1_.resource,
test_resource1_.release_callback);
test_resource1_.Verify();
test_resource2_.ExpectRelease();
pending_layer->PushPropertiesTo(active_layer.get());
active_layer->DidBecomeActive();
test_resource2_.Verify();
test_resource1_.ExpectRelease();
pending_layer->SetTransferableResource(viz::TransferableResource(),
viz::ReleaseCallback());
pending_layer->PushPropertiesTo(active_layer.get());
active_layer->DidBecomeActive();
test_resource1_.Verify();
test_resource1_.ExpectRelease();
pending_layer->SetTransferableResource(test_resource1_.resource,
test_resource1_.release_callback);
}
TEST_F(TextureLayerImplWithResourceTest,
TestDestructorCallbackOnCreatedResource) {
std::unique_ptr<TextureLayerImpl> impl_layer = CreateTextureLayer();
ASSERT_TRUE(impl_layer);
test_resource1_.ExpectRelease();
impl_layer->SetTransferableResource(test_resource1_.resource,
test_resource1_.release_callback);
impl_layer->DidBecomeActive();
EXPECT_TRUE(impl_layer->WillDraw(
DRAW_MODE_HARDWARE, host_impl_.active_tree()->resource_provider()));
impl_layer->DidDraw(host_impl_.active_tree()->resource_provider());
impl_layer->SetTransferableResource(viz::TransferableResource(),
viz::ReleaseCallback());
}
class TextureLayerNoExtraCommitForMailboxTest : public LayerTreeTest,
public TextureLayerClient {
public:
bool PrepareTransferableResource(
viz::TransferableResource* resource,
viz::ReleaseCallback* release_callback) override {
if (layer_tree_host()->SourceFrameNumber() == 1) {
*resource = viz::TransferableResource();
return true;
}
*resource = MakeFakeResource();
*release_callback = base::BindOnce(
&TextureLayerNoExtraCommitForMailboxTest::ResourceReleased,
base::Unretained(this));
return true;
}
void ResourceReleased(const gpu::SyncToken& sync_token, bool lost_resource) {
EXPECT_TRUE(sync_token.HasData());
EndTest();
}
void SetupTree() override {
scoped_refptr<Layer> root = Layer::Create();
root->SetBounds(gfx::Size(10, 10));
root->SetIsDrawable(true);
texture_layer_ = TextureLayer::Create(this);
texture_layer_->SetBounds(gfx::Size(10, 10));
texture_layer_->SetIsDrawable(true);
root->AddChild(texture_layer_);
layer_tree_host()->SetRootLayer(root);
LayerTreeTest::SetupTree();
}
void BeginTest() override { PostSetNeedsCommitToMainThread(); }
void DidCommitAndDrawFrame() override {
switch (layer_tree_host()->SourceFrameNumber()) {
case 1:
EXPECT_FALSE(proxy()->MainFrameWillHappenForTesting());
texture_layer_->SetNeedsDisplay();
break;
case 2:
break;
default:
NOTREACHED();
}
}
private:
scoped_refptr<TextureLayer> texture_layer_;
};
SINGLE_AND_MULTI_THREAD_TEST_F(TextureLayerNoExtraCommitForMailboxTest);
class TextureLayerChangeInvisibleMailboxTest : public LayerTreeTest,
public TextureLayerClient {
public:
TextureLayerChangeInvisibleMailboxTest() : resource_(MakeResource('1')) {}
bool PrepareTransferableResource(
viz::TransferableResource* resource,
viz::ReleaseCallback* release_callback) override {
++prepare_called_;
if (!resource_changed_)
return false;
resource_changed_ = false;
*resource = resource_;
*release_callback = base::BindOnce(
&TextureLayerChangeInvisibleMailboxTest::ResourceReleased,
base::Unretained(this));
return true;
}
viz::TransferableResource MakeResource(char name) {
return MakeFakeResource();
}
void ResourceReleased(const gpu::SyncToken& sync_token, bool lost_resource) {
EXPECT_TRUE(sync_token.HasData());
++resource_returned_;
if (resource_returned_ == 1) {
EXPECT_GE(prepare_called_, 2);
MainThreadTaskRunner()->PostTask(
FROM_HERE,
base::BindOnce(
&TextureLayerChangeInvisibleMailboxTest::ClearTextureLayerClient,
base::Unretained(this)));
return;
}
if (close_on_resource_returned_) {
EXPECT_EQ(2, resource_returned_);
EndTest();
}
}
void ClearTextureLayerClient() { texture_layer_->ClearClient(); }
void SetupTree() override {
scoped_refptr<Layer> root = Layer::Create();
root->SetBounds(gfx::Size(10, 10));
root->SetIsDrawable(true);
solid_layer_ = SolidColorLayer::Create();
solid_layer_->SetBounds(gfx::Size(10, 10));
solid_layer_->SetIsDrawable(true);
solid_layer_->SetBackgroundColor(SkColors::kWhite);
root->AddChild(solid_layer_);
parent_layer_ = Layer::Create();
parent_layer_->SetBounds(gfx::Size(10, 10));
parent_layer_->SetIsDrawable(true);
root->AddChild(parent_layer_);
texture_layer_ = TextureLayer::Create(this);
texture_layer_->SetBounds(gfx::Size(10, 10));
texture_layer_->SetIsDrawable(true);
parent_layer_->AddChild(texture_layer_);
layer_tree_host()->SetRootLayer(root);
LayerTreeTest::SetupTree();
}
void BeginTest() override { PostSetNeedsCommitToMainThread(); }
void DidPresentCompositorFrame(
uint32_t frame_token,
const viz::FrameTimingDetails& frame_timing_details) override {
++presented_count_;
if (presented_count_ == 5) {
if (resource_returned_ < 2) {
close_on_resource_returned_ = true;
} else {
EXPECT_EQ(2, resource_returned_);
EndTest();
}
}
}
void DidCommitAndDrawFrame() override {
++commit_and_draw_count_;
switch (commit_and_draw_count_) {
case 1:
EXPECT_EQ(1, prepare_called_);
parent_layer_->SetOpacity(0.f);
break;
case 2:
EXPECT_EQ(1, prepare_called_);
resource_ = MakeResource('2');
resource_changed_ = true;
texture_layer_->SetNeedsDisplay();
solid_layer_->SetBackgroundColor(SkColors::kGray);
break;
case 3:
EXPECT_EQ(1, prepare_called_);
EXPECT_EQ(0, resource_returned_);
parent_layer_->SetOpacity(0.9f);
break;
case 4:
EXPECT_GE(prepare_called_, 2);
break;
default:
break;
}
}
private:
scoped_refptr<SolidColorLayer> solid_layer_;
scoped_refptr<Layer> parent_layer_;
scoped_refptr<TextureLayer> texture_layer_;
bool resource_changed_ = true;
viz::TransferableResource resource_;
int resource_returned_ = 0;
int prepare_called_ = 0;
int presented_count_ = 0;
int commit_and_draw_count_ = 0;
bool close_on_resource_returned_ = false;
};
#if BUILDFLAG(IS_CHROMEOS)
#define MAYBE_SINGLE_AND_MULTI_THREAD_TEST_F MULTI_THREAD_TEST_F
#else
#define MAYBE_SINGLE_AND_MULTI_THREAD_TEST_F SINGLE_AND_MULTI_THREAD_TEST_F
#endif
MAYBE_SINGLE_AND_MULTI_THREAD_TEST_F(TextureLayerChangeInvisibleMailboxTest);
class TextureLayerReleaseResourcesBase : public LayerTreeTest,
public TextureLayerClient {
public:
bool PrepareTransferableResource(
viz::TransferableResource* resource,
viz::ReleaseCallback* release_callback) override {
if (commit_count_ > 0) {
*resource = viz::TransferableResource();
return true;
}
*resource = MakeFakeResource();
*release_callback =
base::BindOnce(&TextureLayerReleaseResourcesBase::ResourceReleased,
base::Unretained(this));
return true;
}
void ResourceReleased(const gpu::SyncToken& sync_token, bool lost_resource) {
resource_released_ = true;
if (commit_count_ >= 1) {
EndTest();
}
}
void SetupTree() override {
LayerTreeTest::SetupTree();
scoped_refptr<TextureLayer> texture_layer = TextureLayer::Create(this);
texture_layer->SetBounds(gfx::Size(10, 10));
texture_layer->SetIsDrawable(true);
layer_tree_host()->root_layer()->AddChild(texture_layer);
texture_layer_id_ = texture_layer->id();
}
void BeginTest() override {
resource_released_ = false;
commit_count_ = 0;
PostSetNeedsCommitToMainThread();
}
void DidCommitAndDrawFrame() override {
++commit_count_;
PostSetNeedsCommitToMainThread();
}
void AfterTest() override { EXPECT_TRUE(resource_released_); }
protected:
int texture_layer_id_;
int commit_count_ = 0;
private:
bool resource_released_ = false;
};
class TextureLayerReleaseResourcesAfterCommit
: public TextureLayerReleaseResourcesBase {
public:
void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override {
if (commit_count_ == 0) {
auto* texture_impl = static_cast<TextureLayerImpl*>(
host_impl->sync_tree()->LayerById(texture_layer_id_));
EXPECT_FALSE(texture_impl->transferable_resource().is_empty());
texture_impl->ReleaseResources();
EXPECT_TRUE(texture_impl->transferable_resource().is_empty());
}
}
};
SINGLE_AND_MULTI_THREAD_TEST_F(TextureLayerReleaseResourcesAfterCommit);
class TextureLayerReleaseResourcesAfterActivate
: public TextureLayerReleaseResourcesBase {
public:
void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override {
if (commit_count_ == 0) {
auto* texture_impl = static_cast<TextureLayerImpl*>(
host_impl->active_tree()->LayerById(texture_layer_id_));
EXPECT_FALSE(texture_impl->transferable_resource().is_empty());
texture_impl->ReleaseResources();
EXPECT_TRUE(texture_impl->transferable_resource().is_empty());
}
}
};
SINGLE_AND_MULTI_THREAD_TEST_F(TextureLayerReleaseResourcesAfterActivate);
class TextureLayerWithResourceMainThreadDeleted : public LayerTreeTest {
public:
void ReleaseCallback(const gpu::SyncToken& sync_token, bool lost_resource) {
EXPECT_EQ(true, main_thread_.CalledOnValidThread());
EXPECT_FALSE(lost_resource);
++callback_count_;
EndTest();
}
void SetNewFakeResource() {
EXPECT_EQ(true, main_thread_.CalledOnValidThread());
viz::ReleaseCallback callback = base::BindOnce(
&TextureLayerWithResourceMainThreadDeleted::ReleaseCallback,
base::Unretained(this));
auto resource = MakeFakeResource();
layer_->SetTransferableResource(resource, std::move(callback));
}
void SetupTree() override {
gfx::Size bounds(100, 100);
root_ = Layer::Create();
root_->SetBounds(bounds);
layer_ = TextureLayer::Create(nullptr);
layer_->SetIsDrawable(true);
layer_->SetBounds(bounds);
root_->AddChild(layer_);
layer_tree_host()->SetRootLayer(root_);
layer_tree_host()->SetViewportRectAndScale(gfx::Rect(bounds), 1.f,
viz::LocalSurfaceId());
}
void BeginTest() override {
EXPECT_EQ(true, main_thread_.CalledOnValidThread());
callback_count_ = 0;
SetNewFakeResource();
EXPECT_EQ(0, callback_count_);
PostSetNeedsCommitToMainThread();
}
void DidCommitAndDrawFrame() override {
switch (layer_tree_host()->SourceFrameNumber()) {
case 1:
layer_->RemoveFromParent();
layer_ = nullptr;
break;
}
}
void AfterTest() override { EXPECT_EQ(1, callback_count_); }
private:
base::ThreadChecker main_thread_;
int callback_count_;
scoped_refptr<Layer> root_;
scoped_refptr<TextureLayer> layer_;
};
SINGLE_AND_MULTI_THREAD_TEST_F(TextureLayerWithResourceMainThreadDeleted);
class TextureLayerWithResourceImplThreadDeleted : public LayerTreeTest {
public:
void ReleaseCallback(const gpu::SyncToken& sync_token, bool lost_resource) {
EXPECT_EQ(true, main_thread_.CalledOnValidThread());
EXPECT_FALSE(lost_resource);
++callback_count_;
EndTest();
}
void SetNewFakeResource() {
EXPECT_EQ(true, main_thread_.CalledOnValidThread());
viz::ReleaseCallback callback = base::BindOnce(
&TextureLayerWithResourceImplThreadDeleted::ReleaseCallback,
base::Unretained(this));
auto resource = MakeFakeResource();
layer_->SetTransferableResource(resource, std::move(callback));
}
void SetupTree() override {
gfx::Size bounds(100, 100);
root_ = Layer::Create();
root_->SetBounds(bounds);
layer_ = TextureLayer::Create(nullptr);
layer_->SetIsDrawable(true);
layer_->SetBounds(bounds);
root_->AddChild(layer_);
layer_tree_host()->SetRootLayer(root_);
layer_tree_host()->SetViewportRectAndScale(gfx::Rect(bounds), 1.f,
viz::LocalSurfaceId());
}
void BeginTest() override {
EXPECT_EQ(true, main_thread_.CalledOnValidThread());
callback_count_ = 0;
SetNewFakeResource();
EXPECT_EQ(0, callback_count_);
PostSetNeedsCommitToMainThread();
}
void DidCommitAndDrawFrame() override {
switch (layer_tree_host()->SourceFrameNumber()) {
case 1:
layer_->RemoveFromParent();
break;
case 2:
layer_ = nullptr;
break;
}
}
void AfterTest() override { EXPECT_EQ(1, callback_count_); }
private:
base::ThreadChecker main_thread_;
int callback_count_;
scoped_refptr<Layer> root_;
scoped_refptr<TextureLayer> layer_;
};
SINGLE_AND_MULTI_THREAD_TEST_F(TextureLayerWithResourceImplThreadDeleted);
class StubTextureLayerClient : public TextureLayerClient {
public:
bool PrepareTransferableResource(
viz::TransferableResource* resource,
viz::ReleaseCallback* release_callback) override {
return false;
}
};
class SoftwareLayerTreeHostClient : public StubLayerTreeHostClient {
public:
SoftwareLayerTreeHostClient() = default;
~SoftwareLayerTreeHostClient() override = default;
void SetLayerTreeHost(LayerTreeHost* host) { host_ = host; }
void RequestNewLayerTreeFrameSink() override {
auto sink = FakeLayerTreeFrameSink::CreateSoftware();
frame_sink_ = sink.get();
host_->SetLayerTreeFrameSink(std::move(sink));
}
FakeLayerTreeFrameSink* frame_sink() const { return frame_sink_; }
private:
raw_ptr<FakeLayerTreeFrameSink> frame_sink_ = nullptr;
raw_ptr<LayerTreeHost> host_ = nullptr;
};
class SoftwareTextureLayerTest : public LayerTreeTest {
protected:
SoftwareTextureLayerTest() : LayerTreeTest(viz::RendererType::kSoftware) {}
void AfterTest() override {
frame_sink_ = nullptr;
LayerTreeTest::AfterTest();
}
void SetupTree() override {
root_ = Layer::Create();
root_->SetBounds(gfx::Size(10, 10));
solid_color_layer_ = SolidColorLayer::Create();
solid_color_layer_->SetIsDrawable(true);
solid_color_layer_->SetBackgroundColor(SkColors::kRed);
solid_color_layer_->SetBounds(gfx::Size(10, 10));
root_->AddChild(solid_color_layer_);
texture_layer_ = TextureLayer::Create(&client_);
texture_layer_->SetIsDrawable(true);
texture_layer_->SetBounds(gfx::Size(10, 10));
layer_tree_host()->SetRootLayer(root_);
LayerTreeTest::SetupTree();
}
std::unique_ptr<TestLayerTreeFrameSink> CreateLayerTreeFrameSink(
const viz::RendererSettings& renderer_settings,
double refresh_rate,
scoped_refptr<viz::RasterContextProvider> compositor_context_provider,
scoped_refptr<viz::RasterContextProvider> worker_context_provider)
override {
context_provider_sw_ = viz::TestContextProvider::CreateRaster();
gpu::SharedImageInterface* shared_image_interface_sw =
context_provider_sw_->SharedImageInterface();
constexpr bool disable_display_vsync = false;
bool synchronous_composite =
!HasImplThread() &&
!layer_tree_host()->GetSettings().single_thread_proxy_scheduler;
auto sink = std::make_unique<TestLayerTreeFrameSink>(
nullptr, nullptr, shared_image_interface_sw, renderer_settings,
&debug_settings_, task_runner_provider(), synchronous_composite,
disable_display_vsync, refresh_rate);
frame_sink_ = sink.get();
num_frame_sinks_created_++;
return sink;
}
StubTextureLayerClient client_;
scoped_refptr<Layer> root_;
scoped_refptr<SolidColorLayer> solid_color_layer_;
scoped_refptr<TextureLayer> texture_layer_;
raw_ptr<TestLayerTreeFrameSink> frame_sink_ = nullptr;
int num_frame_sinks_created_ = 0;
scoped_refptr<viz::RasterContextProvider> context_provider_sw_;
};
class SoftwareTextureLayerSwitchTreesTest : public SoftwareTextureLayerTest {
protected:
void BeginTest() override {
PostSetNeedsCommitToMainThread();
}
void DidCommitAndDrawFrame() override {
step_ = layer_tree_host()->SourceFrameNumber();
switch (step_) {
case 1: {
root_->AddChild(texture_layer_);
texture_layer_->SetTransferableResource(MakeFakeSoftwareResource(),
base::DoNothing());
} break;
case 2:
texture_layer_->RemoveFromParent();
break;
case 3:
root_->AddChild(texture_layer_);
break;
case 4:
texture_layer_->RemoveFromParent();
root_->AddChild(texture_layer_);
break;
case 5:
texture_layer_->ClearClient();
break;
case 6:
EndTest();
}
}
void DisplayReceivedCompositorFrameOnThread(
const viz::CompositorFrame& frame) override {
verified_frames_++;
}
void AfterTest() override {
EXPECT_EQ(6, verified_frames_);
SoftwareTextureLayerTest::AfterTest();
}
int step_ = 0;
int verified_frames_ = 0;
};
SINGLE_AND_MULTI_THREAD_TEST_F(SoftwareTextureLayerSwitchTreesTest);
class SoftwareTextureLayerPurgeMemoryTest : public SoftwareTextureLayerTest {
protected:
void BeginTest() override {
PostSetNeedsCommitToMainThread();
}
void DidCommitAndDrawFrame() override {
step_ = layer_tree_host()->SourceFrameNumber();
switch (step_) {
case 1: {
root_->AddChild(texture_layer_);
texture_layer_->SetTransferableResource(MakeFakeSoftwareResource(),
base::DoNothing());
}
break;
case 2:
texture_layer_->SetNeedsDisplay();
break;
case 3:
texture_layer_->ClearClient();
break;
case 4:
EndTest();
}
}
void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override {
if (step_ == 1)
base::MemoryPressureListener::SimulatePressureNotification(
base::MEMORY_PRESSURE_LEVEL_CRITICAL);
}
void DisplayReceivedCompositorFrameOnThread(
const viz::CompositorFrame& frame) override {
verified_frames_++;
}
void AfterTest() override {
EXPECT_EQ(4, verified_frames_);
SoftwareTextureLayerTest::AfterTest();
}
int step_ = 0;
int verified_frames_ = 0;
};
SINGLE_THREAD_TEST_F(SoftwareTextureLayerPurgeMemoryTest);
class SoftwareTextureLayerMultipleResourceTest
: public SoftwareTextureLayerTest {
protected:
void BeginTest() override {
PostSetNeedsCommitToMainThread();
}
void DidCommitAndDrawFrame() override {
step_ = layer_tree_host()->SourceFrameNumber();
switch (step_) {
case 1: {
root_->AddChild(texture_layer_);
texture_layer_->SetTransferableResource(MakeFakeSoftwareResource(),
base::DoNothing());
texture_layer_->SetTransferableResource(MakeFakeSoftwareResource(),
base::DoNothing());
} break;
case 2:
texture_layer_->SetNeedsDisplay();
break;
case 3:
texture_layer_->ClearClient();
break;
case 4:
EndTest();
}
}
void DisplayReceivedCompositorFrameOnThread(
const viz::CompositorFrame& frame) override {
verified_frames_++;
}
void AfterTest() override {
EXPECT_EQ(4, verified_frames_);
SoftwareTextureLayerTest::AfterTest();
}
int step_ = 0;
int verified_frames_ = 0;
};
SINGLE_AND_MULTI_THREAD_TEST_F(SoftwareTextureLayerMultipleResourceTest);
class SoftwareTextureLayerLoseFrameSinkTest : public SoftwareTextureLayerTest {
protected:
void BeginTest() override {
PostSetNeedsCommitToMainThread();
}
void DidCommitAndDrawFrame() override {
MainThreadTaskRunner()->PostTask(
FROM_HERE,
base::BindOnce(&SoftwareTextureLayerLoseFrameSinkTest::NextStep,
base::Unretained(this)));
}
void NextStep() {
step_ = layer_tree_host()->SourceFrameNumber();
switch (step_) {
case 1: {
root_->AddChild(texture_layer_);
auto release_callback = base::BindOnce(
&SoftwareTextureLayerLoseFrameSinkTest::ReleaseCallback,
base::Unretained(this));
texture_layer_->SetTransferableResource(MakeFakeSoftwareResource(),
std::move(release_callback));
EXPECT_FALSE(released_);
} break;
case 2:
layer_tree_host()->SetVisible(false);
frame_sink_ = nullptr;
layer_tree_host()->ReleaseLayerTreeFrameSink();
layer_tree_host()->SetVisible(true);
texture_layer_->SetNeedsDisplay();
EXPECT_FALSE(released_);
break;
case 3:
EXPECT_FALSE(released_);
texture_layer_->ClearClient();
}
}
void DisplayReceivedCompositorFrameOnThread(
const viz::CompositorFrame& frame) override {
verified_frames_++;
}
void WillCommit(const CommitState& commit_state) override {
source_frame_number_ = commit_state.source_frame_number;
}
void ReleaseCallback(const gpu::SyncToken& sync_token, bool lost) {
EXPECT_EQ(source_frame_number_, 3);
released_ = true;
EndTest();
}
void AfterTest() override {
EXPECT_EQ(4, verified_frames_);
SoftwareTextureLayerTest::AfterTest();
}
int step_ = 0;
int verified_frames_ = 0;
int source_frame_number_ = 0;
bool released_ = false;
};
SINGLE_AND_MULTI_THREAD_TEST_F(SoftwareTextureLayerLoseFrameSinkTest);
class TextureLayerNoResourceTest : public LayerTreeTest, TextureLayerClient {
public:
bool PrepareTransferableResource(
viz::TransferableResource* transferable_resource,
viz::ReleaseCallback* release_callback) override {
return false;
}
void SetupTree() override {
SetInitialRootBounds(gfx::Size(100, 100));
LayerTreeTest::SetupTree();
auto texture_layer = TextureLayer::Create(this);
texture_layer->SetIsDrawable(true);
texture_layer->SetContentsOpaque(true);
texture_layer->SetBounds(gfx::Size(100, 100));
texture_layer->SetBackgroundColor(SkColors::kRed);
layer_tree_host()->root_layer()->AddChild(texture_layer);
texture_layer_id_ = static_cast<uint32_t>(texture_layer->id());
}
void BeginTest() override { PostSetNeedsCommitToMainThread(); }
void DisplayReceivedCompositorFrameOnThread(
const viz::CompositorFrame& frame) override {
EXPECT_EQ(0u, frame.resource_list.size());
EXPECT_EQ(1u, frame.render_pass_list.size());
const auto& quad_list = frame.render_pass_list[0]->quad_list;
EXPECT_EQ(1u, quad_list.size());
EXPECT_NE(viz::DrawQuad::Material::kTextureContent,
quad_list.ElementAt(0)->material);
const auto& shared_list = frame.render_pass_list[0]->shared_quad_state_list;
EXPECT_EQ(1u, shared_list.size());
EXPECT_NE(texture_layer_id_, shared_list.ElementAt(0)->layer_id);
EndTest();
}
private:
uint32_t texture_layer_id_;
};
SINGLE_AND_MULTI_THREAD_TEST_F(TextureLayerNoResourceTest);
}
}