blob: bc09d93f7144dd373da7c35535d795c81d1e6543 [file] [log] [blame]
// Copyright 2012 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 "cc/texture_layer.h"
#include <string>
#include "base/callback.h"
#include "cc/layer_tree_host.h"
#include "cc/layer_tree_impl.h"
#include "cc/single_thread_proxy.h"
#include "cc/test/fake_impl_proxy.h"
#include "cc/test/fake_layer_tree_host_client.h"
#include "cc/test/fake_layer_tree_host_impl.h"
#include "cc/test/layer_tree_test_common.h"
#include "cc/texture_layer_impl.h"
#include "cc/thread.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using ::testing::Mock;
using ::testing::_;
using ::testing::AtLeast;
using ::testing::AnyNumber;
namespace cc {
namespace {
class MockLayerImplTreeHost : public LayerTreeHost {
public:
MockLayerImplTreeHost()
: LayerTreeHost(&m_fakeClient, LayerTreeSettings())
{
initialize(scoped_ptr<Thread>(NULL));
}
MOCK_METHOD0(acquireLayerTextures, void());
MOCK_METHOD0(setNeedsCommit, void());
private:
FakeLayerImplTreeHostClient m_fakeClient;
};
class TextureLayerTest : public testing::Test {
public:
TextureLayerTest()
: m_hostImpl(&m_proxy)
{
}
protected:
virtual void SetUp()
{
m_layerTreeHost.reset(new MockLayerImplTreeHost);
}
virtual void TearDown()
{
Mock::VerifyAndClearExpectations(m_layerTreeHost.get());
EXPECT_CALL(*m_layerTreeHost, acquireLayerTextures()).Times(AnyNumber());
EXPECT_CALL(*m_layerTreeHost, setNeedsCommit()).Times(AnyNumber());
m_layerTreeHost->setRootLayer(0);
m_layerTreeHost.reset();
}
scoped_ptr<MockLayerImplTreeHost> m_layerTreeHost;
FakeImplProxy m_proxy;
FakeLayerTreeHostImpl m_hostImpl;
};
TEST_F(TextureLayerTest, syncImplWhenChangingTextureId)
{
scoped_refptr<TextureLayer> testLayer = TextureLayer::create(0);
ASSERT_TRUE(testLayer);
EXPECT_CALL(*m_layerTreeHost, acquireLayerTextures()).Times(AnyNumber());
EXPECT_CALL(*m_layerTreeHost, setNeedsCommit()).Times(AnyNumber());
m_layerTreeHost->setRootLayer(testLayer);
Mock::VerifyAndClearExpectations(m_layerTreeHost.get());
EXPECT_EQ(testLayer->layerTreeHost(), m_layerTreeHost.get());
EXPECT_CALL(*m_layerTreeHost, acquireLayerTextures()).Times(0);
EXPECT_CALL(*m_layerTreeHost, setNeedsCommit()).Times(AtLeast(1));
testLayer->setTextureId(1);
Mock::VerifyAndClearExpectations(m_layerTreeHost.get());
EXPECT_CALL(*m_layerTreeHost, acquireLayerTextures()).Times(AtLeast(1));
EXPECT_CALL(*m_layerTreeHost, setNeedsCommit()).Times(AtLeast(1));
testLayer->setTextureId(2);
Mock::VerifyAndClearExpectations(m_layerTreeHost.get());
EXPECT_CALL(*m_layerTreeHost, acquireLayerTextures()).Times(AtLeast(1));
EXPECT_CALL(*m_layerTreeHost, setNeedsCommit()).Times(AtLeast(1));
testLayer->setTextureId(0);
Mock::VerifyAndClearExpectations(m_layerTreeHost.get());
}
TEST_F(TextureLayerTest, syncImplWhenDrawing)
{
gfx::RectF dirtyRect(0, 0, 1, 1);
scoped_refptr<TextureLayer> testLayer = TextureLayer::create(0);
ASSERT_TRUE(testLayer);
scoped_ptr<TextureLayerImpl> implLayer;
implLayer = TextureLayerImpl::create(m_hostImpl.activeTree(), 1, false);
ASSERT_TRUE(implLayer);
EXPECT_CALL(*m_layerTreeHost, acquireLayerTextures()).Times(AnyNumber());
EXPECT_CALL(*m_layerTreeHost, setNeedsCommit()).Times(AnyNumber());
m_layerTreeHost->setRootLayer(testLayer);
testLayer->setTextureId(1);
testLayer->setIsDrawable(true);
Mock::VerifyAndClearExpectations(m_layerTreeHost.get());
EXPECT_EQ(testLayer->layerTreeHost(), m_layerTreeHost.get());
EXPECT_CALL(*m_layerTreeHost, acquireLayerTextures()).Times(1);
EXPECT_CALL(*m_layerTreeHost, setNeedsCommit()).Times(0);
testLayer->willModifyTexture();
Mock::VerifyAndClearExpectations(m_layerTreeHost.get());
EXPECT_CALL(*m_layerTreeHost, acquireLayerTextures()).Times(0);
EXPECT_CALL(*m_layerTreeHost, setNeedsCommit()).Times(1);
testLayer->setNeedsDisplayRect(dirtyRect);
Mock::VerifyAndClearExpectations(m_layerTreeHost.get());
EXPECT_CALL(*m_layerTreeHost, acquireLayerTextures()).Times(0);
EXPECT_CALL(*m_layerTreeHost, setNeedsCommit()).Times(1);
testLayer->pushPropertiesTo(implLayer.get()); // fake commit
testLayer->setIsDrawable(false);
Mock::VerifyAndClearExpectations(m_layerTreeHost.get());
// Verify that non-drawable layers don't signal the compositor,
// except for the first draw after last commit, which must acquire
// the texture.
EXPECT_CALL(*m_layerTreeHost, acquireLayerTextures()).Times(1);
EXPECT_CALL(*m_layerTreeHost, setNeedsCommit()).Times(0);
testLayer->willModifyTexture();
testLayer->setNeedsDisplayRect(dirtyRect);
testLayer->pushPropertiesTo(implLayer.get()); // fake commit
Mock::VerifyAndClearExpectations(m_layerTreeHost.get());
// Second draw with layer in non-drawable state: no texture
// acquisition.
EXPECT_CALL(*m_layerTreeHost, acquireLayerTextures()).Times(0);
EXPECT_CALL(*m_layerTreeHost, setNeedsCommit()).Times(0);
testLayer->willModifyTexture();
testLayer->setNeedsDisplayRect(dirtyRect);
Mock::VerifyAndClearExpectations(m_layerTreeHost.get());
}
TEST_F(TextureLayerTest, syncImplWhenRemovingFromTree)
{
scoped_refptr<Layer> rootLayer = Layer::create();
ASSERT_TRUE(rootLayer);
scoped_refptr<Layer> childLayer = Layer::create();
ASSERT_TRUE(childLayer);
rootLayer->addChild(childLayer);
scoped_refptr<TextureLayer> testLayer = TextureLayer::create(0);
ASSERT_TRUE(testLayer);
testLayer->setTextureId(0);
childLayer->addChild(testLayer);
EXPECT_CALL(*m_layerTreeHost, acquireLayerTextures()).Times(AnyNumber());
EXPECT_CALL(*m_layerTreeHost, setNeedsCommit()).Times(AnyNumber());
m_layerTreeHost->setRootLayer(rootLayer);
Mock::VerifyAndClearExpectations(m_layerTreeHost.get());
EXPECT_CALL(*m_layerTreeHost, acquireLayerTextures()).Times(0);
EXPECT_CALL(*m_layerTreeHost, setNeedsCommit()).Times(AtLeast(1));
testLayer->removeFromParent();
Mock::VerifyAndClearExpectations(m_layerTreeHost.get());
EXPECT_CALL(*m_layerTreeHost, acquireLayerTextures()).Times(0);
EXPECT_CALL(*m_layerTreeHost, setNeedsCommit()).Times(AtLeast(1));
childLayer->addChild(testLayer);
Mock::VerifyAndClearExpectations(m_layerTreeHost.get());
EXPECT_CALL(*m_layerTreeHost, acquireLayerTextures()).Times(0);
EXPECT_CALL(*m_layerTreeHost, setNeedsCommit()).Times(AtLeast(1));
testLayer->setTextureId(1);
Mock::VerifyAndClearExpectations(m_layerTreeHost.get());
EXPECT_CALL(*m_layerTreeHost, acquireLayerTextures()).Times(AtLeast(1));
EXPECT_CALL(*m_layerTreeHost, setNeedsCommit()).Times(AtLeast(1));
testLayer->removeFromParent();
Mock::VerifyAndClearExpectations(m_layerTreeHost.get());
}
class MockMailboxCallback {
public:
MOCK_METHOD2(Release, void(const std::string& mailbox, unsigned syncPoint));
};
struct CommonMailboxObjects {
CommonMailboxObjects()
: m_mailboxName1(64, '1')
, m_mailboxName2(64, '2')
, m_syncPoint1(1)
, m_syncPoint2(2)
{
m_releaseMailbox1 = base::Bind(&MockMailboxCallback::Release,
base::Unretained(&m_mockCallback),
m_mailboxName1);
m_releaseMailbox2 = base::Bind(&MockMailboxCallback::Release,
base::Unretained(&m_mockCallback),
m_mailboxName2);
Mailbox m1;
m1.setName(reinterpret_cast<const int8*>(m_mailboxName1.data()));
m_mailbox1 = TextureMailbox(m1, m_releaseMailbox1, m_syncPoint1);
Mailbox m2;
m2.setName(reinterpret_cast<const int8*>(m_mailboxName2.data()));
m_mailbox2 = TextureMailbox(m2, m_releaseMailbox2, m_syncPoint2);
}
std::string m_mailboxName1;
std::string m_mailboxName2;
MockMailboxCallback m_mockCallback;
TextureMailbox::ReleaseCallback m_releaseMailbox1;
TextureMailbox::ReleaseCallback m_releaseMailbox2;
TextureMailbox m_mailbox1;
TextureMailbox m_mailbox2;
unsigned m_syncPoint1;
unsigned m_syncPoint2;
};
class TextureLayerWithMailboxTest : public TextureLayerTest {
protected:
virtual void TearDown()
{
Mock::VerifyAndClearExpectations(&m_testData.m_mockCallback);
EXPECT_CALL(m_testData.m_mockCallback,
Release(m_testData.m_mailboxName1,
m_testData.m_syncPoint1)).Times(1);
TextureLayerTest::TearDown();
}
CommonMailboxObjects m_testData;
};
TEST_F(TextureLayerWithMailboxTest, replaceMailboxOnMainThreadBeforeCommit)
{
scoped_refptr<TextureLayer> testLayer = TextureLayer::createForMailbox();
ASSERT_TRUE(testLayer);
EXPECT_CALL(*m_layerTreeHost, acquireLayerTextures()).Times(0);
EXPECT_CALL(*m_layerTreeHost, setNeedsCommit()).Times(AnyNumber());
m_layerTreeHost->setRootLayer(testLayer);
Mock::VerifyAndClearExpectations(m_layerTreeHost.get());
EXPECT_CALL(*m_layerTreeHost, acquireLayerTextures()).Times(0);
EXPECT_CALL(*m_layerTreeHost, setNeedsCommit()).Times(AtLeast(1));
testLayer->setTextureMailbox(m_testData.m_mailbox1);
Mock::VerifyAndClearExpectations(m_layerTreeHost.get());
EXPECT_CALL(*m_layerTreeHost, acquireLayerTextures()).Times(0);
EXPECT_CALL(*m_layerTreeHost, setNeedsCommit()).Times(AtLeast(1));
EXPECT_CALL(m_testData.m_mockCallback,
Release(m_testData.m_mailboxName1,
m_testData.m_syncPoint1)).Times(1);
testLayer->setTextureMailbox(m_testData.m_mailbox2);
Mock::VerifyAndClearExpectations(m_layerTreeHost.get());
Mock::VerifyAndClearExpectations(&m_testData.m_mockCallback);
EXPECT_CALL(*m_layerTreeHost, acquireLayerTextures()).Times(0);
EXPECT_CALL(*m_layerTreeHost, setNeedsCommit()).Times(AtLeast(1));
EXPECT_CALL(m_testData.m_mockCallback,
Release(m_testData.m_mailboxName2,
m_testData.m_syncPoint2)).Times(1);
testLayer->setTextureMailbox(TextureMailbox());
Mock::VerifyAndClearExpectations(m_layerTreeHost.get());
Mock::VerifyAndClearExpectations(&m_testData.m_mockCallback);
// Test destructor.
EXPECT_CALL(*m_layerTreeHost, setNeedsCommit()).Times(AtLeast(1));
testLayer->setTextureMailbox(m_testData.m_mailbox1);
}
class TextureLayerImplWithMailboxThreadedCallback : public ThreadedTest {
public:
TextureLayerImplWithMailboxThreadedCallback()
: m_resetMailbox(false)
{
}
// Make sure callback is received on main and doesn't block the impl thread.
void releaseCallback(unsigned syncPoint) {
EXPECT_EQ(true, proxy()->isMainThread());
endTest();
}
virtual void beginTest() OVERRIDE
{
m_layer = TextureLayer::createForMailbox();
m_layer->setIsDrawable(true);
m_layerTreeHost->setRootLayer(m_layer);
TextureMailbox mailbox(
std::string(64, '1'),
base::Bind(
&TextureLayerImplWithMailboxThreadedCallback::releaseCallback,
base::Unretained(this)));
m_layer->setTextureMailbox(mailbox);
postSetNeedsCommitToMainThread();
}
virtual void didCommit() OVERRIDE
{
if (m_resetMailbox)
return;
m_layer->setTextureMailbox(TextureMailbox());
m_resetMailbox = true;
}
virtual void afterTest() OVERRIDE
{
}
private:
bool m_resetMailbox;
scoped_refptr<TextureLayer> m_layer;
};
SINGLE_AND_MULTI_THREAD_TEST_F(TextureLayerImplWithMailboxThreadedCallback);
class TextureLayerImplWithMailboxTest : public TextureLayerTest {
protected:
virtual void SetUp()
{
TextureLayerTest::SetUp();
m_layerTreeHost.reset(new MockLayerImplTreeHost);
EXPECT_TRUE(m_hostImpl.initializeRenderer(createFakeOutputSurface()));
}
CommonMailboxObjects m_testData;
};
TEST_F(TextureLayerImplWithMailboxTest, testImplLayerCallbacks)
{
scoped_ptr<TextureLayerImpl> implLayer;
implLayer = TextureLayerImpl::create(m_hostImpl.activeTree(), 1, true);
ASSERT_TRUE(implLayer);
// Test setting identical mailbox.
EXPECT_CALL(m_testData.m_mockCallback, Release(_, _)).Times(0);
implLayer->setTextureMailbox(m_testData.m_mailbox1);
implLayer->setTextureMailbox(m_testData.m_mailbox1);
Mock::VerifyAndClearExpectations(&m_testData.m_mockCallback);
// Test multiple commits without a draw.
EXPECT_CALL(m_testData.m_mockCallback,
Release(m_testData.m_mailboxName1,
m_testData.m_syncPoint1)).Times(1);
implLayer->setTextureMailbox(m_testData.m_mailbox2);
Mock::VerifyAndClearExpectations(&m_testData.m_mockCallback);
// Test resetting the mailbox.
EXPECT_CALL(m_testData.m_mockCallback,
Release(m_testData.m_mailboxName2,
m_testData.m_syncPoint2)).Times(1);
implLayer->setTextureMailbox(TextureMailbox());
Mock::VerifyAndClearExpectations(&m_testData.m_mockCallback);
// Test destructor.
EXPECT_CALL(m_testData.m_mockCallback,
Release(m_testData.m_mailboxName1,
m_testData.m_syncPoint1)).Times(1);
implLayer->setTextureMailbox(m_testData.m_mailbox1);
}
TEST_F(TextureLayerImplWithMailboxTest, testDestructorCallbackOnCreatedResource)
{
scoped_ptr<TextureLayerImpl> implLayer;
implLayer = TextureLayerImpl::create(m_hostImpl.activeTree(), 1, true);
ASSERT_TRUE(implLayer);
EXPECT_CALL(m_testData.m_mockCallback,
Release(m_testData.m_mailboxName1, _)).Times(1);
implLayer->setTextureMailbox(m_testData.m_mailbox1);
implLayer->willDraw(m_hostImpl.activeTree()->resource_provider());
implLayer->didDraw(m_hostImpl.activeTree()->resource_provider());
implLayer->setTextureMailbox(TextureMailbox());
}
TEST_F(TextureLayerImplWithMailboxTest, testCallbackOnInUseResource)
{
ResourceProvider *provider = m_hostImpl.activeTree()->resource_provider();
ResourceProvider::ResourceId id =
provider->createResourceFromTextureMailbox(m_testData.m_mailbox1);
provider->allocateForTesting(id);
// Transfer some resources to the parent.
ResourceProvider::ResourceIdArray resourceIdsToTransfer;
resourceIdsToTransfer.push_back(id);
TransferableResourceList list;
provider->prepareSendToParent(resourceIdsToTransfer, &list);
EXPECT_TRUE(provider->inUseByConsumer(id));
EXPECT_CALL(m_testData.m_mockCallback, Release(_, _)).Times(0);
provider->deleteResource(id);
Mock::VerifyAndClearExpectations(&m_testData.m_mockCallback);
EXPECT_CALL(m_testData.m_mockCallback,
Release(m_testData.m_mailboxName1, _)).Times(1);
provider->receiveFromParent(list);
}
} // namespace
} // namespace cc