summaryrefslogtreecommitdiff
path: root/chromium/cc/layers/texture_layer_unittest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/cc/layers/texture_layer_unittest.cc')
-rw-r--r--chromium/cc/layers/texture_layer_unittest.cc1120
1 files changed, 1036 insertions, 84 deletions
diff --git a/chromium/cc/layers/texture_layer_unittest.cc b/chromium/cc/layers/texture_layer_unittest.cc
index aa08e9f81ee..239c5b8fa22 100644
--- a/chromium/cc/layers/texture_layer_unittest.cc
+++ b/chromium/cc/layers/texture_layer_unittest.cc
@@ -4,16 +4,28 @@
#include "cc/layers/texture_layer.h"
+#include <algorithm>
#include <string>
+#include "base/bind.h"
#include "base/callback.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread.h"
+#include "base/time/time.h"
+#include "cc/debug/test_web_graphics_context_3d.h"
+#include "cc/layers/solid_color_layer.h"
#include "cc/layers/texture_layer_client.h"
#include "cc/layers/texture_layer_impl.h"
+#include "cc/output/compositor_frame_ack.h"
+#include "cc/output/context_provider.h"
+#include "cc/resources/returned_resource.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/fake_output_surface.h"
#include "cc/test/layer_test_common.h"
#include "cc/test/layer_tree_test.h"
+#include "cc/trees/blocking_task_runner.h"
#include "cc/trees/layer_tree_host.h"
#include "cc/trees/layer_tree_impl.h"
#include "cc/trees/single_thread_proxy.h"
@@ -187,7 +199,7 @@ TEST_F(TextureLayerTest, SyncImplWhenRemovingFromTree) {
TEST_F(TextureLayerTest, CheckPropertyChangeCausesCorrectBehavior) {
scoped_refptr<TextureLayer> test_layer = TextureLayer::Create(NULL);
- layer_tree_host_->SetRootLayer(test_layer);
+ EXPECT_SET_NEEDS_COMMIT(1, layer_tree_host_->SetRootLayer(test_layer));
// Test properties that should call SetNeedsCommit. All properties need to
// be set to new values in order for SetNeedsCommit to be called.
@@ -243,9 +255,12 @@ class FakeTextureLayerClient : public TextureLayerClient {
return context_.get();
}
- virtual bool PrepareTextureMailbox(TextureMailbox* mailbox,
- bool use_shared_memory) OVERRIDE {
+ virtual bool PrepareTextureMailbox(
+ TextureMailbox* mailbox,
+ scoped_ptr<SingleReleaseCallback>* release_callback,
+ bool use_shared_memory) OVERRIDE {
*mailbox = TextureMailbox();
+ *release_callback = scoped_ptr<SingleReleaseCallback>();
return true;
}
@@ -328,25 +343,25 @@ struct CommonMailboxObjects {
mailbox_name2_);
gpu::Mailbox m1;
m1.SetName(reinterpret_cast<const int8*>(mailbox_name1_.data()));
- mailbox1_ = TextureMailbox(m1, release_mailbox1_, sync_point1_);
+ mailbox1_ = TextureMailbox(m1, sync_point1_);
gpu::Mailbox m2;
m2.SetName(reinterpret_cast<const int8*>(mailbox_name2_.data()));
- mailbox2_ = TextureMailbox(m2, release_mailbox2_, sync_point2_);
+ mailbox2_ = TextureMailbox(m2, sync_point2_);
gfx::Size size(128, 128);
EXPECT_TRUE(shared_memory_->CreateAndMapAnonymous(4 * size.GetArea()));
release_mailbox3_ = base::Bind(&MockMailboxCallback::Release2,
base::Unretained(&mock_callback_),
shared_memory_.get());
- mailbox3_ = TextureMailbox(shared_memory_.get(), size, release_mailbox3_);
+ mailbox3_ = TextureMailbox(shared_memory_.get(), size);
}
std::string mailbox_name1_;
std::string mailbox_name2_;
MockMailboxCallback mock_callback_;
- TextureMailbox::ReleaseCallback release_mailbox1_;
- TextureMailbox::ReleaseCallback release_mailbox2_;
- TextureMailbox::ReleaseCallback release_mailbox3_;
+ ReleaseCallback release_mailbox1_;
+ ReleaseCallback release_mailbox2_;
+ ReleaseCallback release_mailbox3_;
TextureMailbox mailbox1_;
TextureMailbox mailbox2_;
TextureMailbox mailbox3_;
@@ -355,6 +370,14 @@ struct CommonMailboxObjects {
scoped_ptr<base::SharedMemory> shared_memory_;
};
+class TestMailboxHolder : public TextureLayer::MailboxHolder {
+ public:
+ using TextureLayer::MailboxHolder::Create;
+
+ protected:
+ virtual ~TestMailboxHolder() {}
+};
+
class TextureLayerWithMailboxTest : public TextureLayerTest {
protected:
virtual void TearDown() {
@@ -380,7 +403,9 @@ TEST_F(TextureLayerWithMailboxTest, ReplaceMailboxOnMainThreadBeforeCommit) {
EXPECT_CALL(*layer_tree_host_, AcquireLayerTextures()).Times(0);
EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AtLeast(1));
- test_layer->SetTextureMailbox(test_data_.mailbox1_);
+ test_layer->SetTextureMailbox(
+ test_data_.mailbox1_,
+ SingleReleaseCallback::Create(test_data_.release_mailbox1_));
Mock::VerifyAndClearExpectations(layer_tree_host_.get());
EXPECT_CALL(*layer_tree_host_, AcquireLayerTextures()).Times(0);
@@ -390,7 +415,9 @@ TEST_F(TextureLayerWithMailboxTest, ReplaceMailboxOnMainThreadBeforeCommit) {
test_data_.sync_point1_,
false))
.Times(1);
- test_layer->SetTextureMailbox(test_data_.mailbox2_);
+ test_layer->SetTextureMailbox(
+ test_data_.mailbox2_,
+ SingleReleaseCallback::Create(test_data_.release_mailbox2_));
Mock::VerifyAndClearExpectations(layer_tree_host_.get());
Mock::VerifyAndClearExpectations(&test_data_.mock_callback_);
@@ -401,11 +428,16 @@ TEST_F(TextureLayerWithMailboxTest, ReplaceMailboxOnMainThreadBeforeCommit) {
test_data_.sync_point2_,
false))
.Times(1);
- test_layer->SetTextureMailbox(TextureMailbox());
+ test_layer->SetTextureMailbox(TextureMailbox(),
+ scoped_ptr<SingleReleaseCallback>());
Mock::VerifyAndClearExpectations(layer_tree_host_.get());
Mock::VerifyAndClearExpectations(&test_data_.mock_callback_);
- test_layer->SetTextureMailbox(test_data_.mailbox3_);
+ EXPECT_CALL(*layer_tree_host_, AcquireLayerTextures()).Times(0);
+ EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AtLeast(1));
+ test_layer->SetTextureMailbox(
+ test_data_.mailbox3_,
+ SingleReleaseCallback::Create(test_data_.release_mailbox3_));
Mock::VerifyAndClearExpectations(layer_tree_host_.get());
Mock::VerifyAndClearExpectations(&test_data_.mock_callback_);
@@ -415,13 +447,309 @@ TEST_F(TextureLayerWithMailboxTest, ReplaceMailboxOnMainThreadBeforeCommit) {
Release2(test_data_.shared_memory_.get(),
0, false))
.Times(1);
- test_layer->SetTextureMailbox(TextureMailbox());
+ test_layer->SetTextureMailbox(TextureMailbox(),
+ scoped_ptr<SingleReleaseCallback>());
Mock::VerifyAndClearExpectations(layer_tree_host_.get());
Mock::VerifyAndClearExpectations(&test_data_.mock_callback_);
// Test destructor.
EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AtLeast(1));
- test_layer->SetTextureMailbox(test_data_.mailbox1_);
+ test_layer->SetTextureMailbox(
+ test_data_.mailbox1_,
+ SingleReleaseCallback::Create(test_data_.release_mailbox1_));
+}
+
+class TextureLayerMailboxHolderTest : public TextureLayerTest {
+ public:
+ TextureLayerMailboxHolderTest()
+ : main_thread_("MAIN") {
+ main_thread_.Start();
+ }
+
+ void Wait(const base::Thread& thread) {
+ bool manual_reset = false;
+ bool initially_signaled = false;
+ base::WaitableEvent event(manual_reset, initially_signaled);
+ thread.message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&base::WaitableEvent::Signal, base::Unretained(&event)));
+ event.Wait();
+ }
+
+ void CreateMainRef() {
+ main_ref_ = TestMailboxHolder::Create(
+ test_data_.mailbox1_,
+ SingleReleaseCallback::Create(test_data_.release_mailbox1_)).Pass();
+ }
+
+ void ReleaseMainRef() {
+ main_ref_.reset();
+ }
+
+ void CreateImplRef(scoped_ptr<SingleReleaseCallback>* impl_ref) {
+ *impl_ref = main_ref_->holder()->GetCallbackForImplThread();
+ }
+
+ void CapturePostTasksAndWait(base::WaitableEvent* begin_capture,
+ base::WaitableEvent* wait_for_capture,
+ base::WaitableEvent* stop_capture) {
+ begin_capture->Wait();
+ BlockingTaskRunner::CapturePostTasks capture;
+ wait_for_capture->Signal();
+ stop_capture->Wait();
+ }
+
+ protected:
+ scoped_ptr<TestMailboxHolder::MainThreadReference>
+ main_ref_;
+ base::Thread main_thread_;
+ CommonMailboxObjects test_data_;
+};
+
+TEST_F(TextureLayerMailboxHolderTest, TwoCompositors_BothReleaseThenMain) {
+ scoped_refptr<TextureLayer> test_layer = TextureLayer::CreateForMailbox(NULL);
+ ASSERT_TRUE(test_layer.get());
+
+ main_thread_.message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&TextureLayerMailboxHolderTest::CreateMainRef,
+ base::Unretained(this)));
+
+ Wait(main_thread_);
+
+ // The texture layer is attached to compositor1, and passes a reference to its
+ // impl tree.
+ scoped_ptr<SingleReleaseCallback> compositor1;
+ main_thread_.message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&TextureLayerMailboxHolderTest::CreateImplRef,
+ base::Unretained(this),
+ &compositor1));
+
+ // Then the texture layer is removed and attached to compositor2, and passes a
+ // reference to its impl tree.
+ scoped_ptr<SingleReleaseCallback> compositor2;
+ main_thread_.message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&TextureLayerMailboxHolderTest::CreateImplRef,
+ base::Unretained(this),
+ &compositor2));
+
+ Wait(main_thread_);
+ Mock::VerifyAndClearExpectations(&test_data_.mock_callback_);
+
+ // The compositors both destroy their impl trees before the main thread layer
+ // is destroyed.
+ compositor1->Run(100, false);
+ compositor2->Run(200, false);
+
+ Wait(main_thread_);
+
+ EXPECT_CALL(test_data_.mock_callback_, Release(_, _, _)).Times(0);
+ Mock::VerifyAndClearExpectations(&test_data_.mock_callback_);
+
+ // The main thread ref is the last one, so the mailbox is released back to the
+ // embedder, with the last sync point provided by the impl trees.
+ EXPECT_CALL(test_data_.mock_callback_,
+ Release(test_data_.mailbox_name1_, 200, false)).Times(1);
+
+ main_thread_.message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&TextureLayerMailboxHolderTest::ReleaseMainRef,
+ base::Unretained(this)));
+ Wait(main_thread_);
+ Mock::VerifyAndClearExpectations(&test_data_.mock_callback_);
+}
+
+TEST_F(TextureLayerMailboxHolderTest, TwoCompositors_MainReleaseBetween) {
+ scoped_refptr<TextureLayer> test_layer = TextureLayer::CreateForMailbox(NULL);
+ ASSERT_TRUE(test_layer.get());
+
+ main_thread_.message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&TextureLayerMailboxHolderTest::CreateMainRef,
+ base::Unretained(this)));
+
+ Wait(main_thread_);
+
+ // The texture layer is attached to compositor1, and passes a reference to its
+ // impl tree.
+ scoped_ptr<SingleReleaseCallback> compositor1;
+ main_thread_.message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&TextureLayerMailboxHolderTest::CreateImplRef,
+ base::Unretained(this),
+ &compositor1));
+
+ // Then the texture layer is removed and attached to compositor2, and passes a
+ // reference to its impl tree.
+ scoped_ptr<SingleReleaseCallback> compositor2;
+ main_thread_.message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&TextureLayerMailboxHolderTest::CreateImplRef,
+ base::Unretained(this),
+ &compositor2));
+
+ Wait(main_thread_);
+ Mock::VerifyAndClearExpectations(&test_data_.mock_callback_);
+
+ // One compositor destroys their impl tree.
+ compositor1->Run(100, false);
+
+ // Then the main thread reference is destroyed.
+ main_thread_.message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&TextureLayerMailboxHolderTest::ReleaseMainRef,
+ base::Unretained(this)));
+
+ Wait(main_thread_);
+
+ EXPECT_CALL(test_data_.mock_callback_, Release(_, _, _)).Times(0);
+ Mock::VerifyAndClearExpectations(&test_data_.mock_callback_);
+
+ // The second impl reference is destroyed last, causing the mailbox to be
+ // released back to the embedder with the last sync point from the impl tree.
+ EXPECT_CALL(test_data_.mock_callback_,
+ Release(test_data_.mailbox_name1_, 200, true)).Times(1);
+
+ compositor2->Run(200, true);
+ Wait(main_thread_);
+ Mock::VerifyAndClearExpectations(&test_data_.mock_callback_);
+}
+
+TEST_F(TextureLayerMailboxHolderTest, TwoCompositors_MainReleasedFirst) {
+ scoped_refptr<TextureLayer> test_layer = TextureLayer::CreateForMailbox(NULL);
+ ASSERT_TRUE(test_layer.get());
+
+ main_thread_.message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&TextureLayerMailboxHolderTest::CreateMainRef,
+ base::Unretained(this)));
+
+ Wait(main_thread_);
+
+ // The texture layer is attached to compositor1, and passes a reference to its
+ // impl tree.
+ scoped_ptr<SingleReleaseCallback> compositor1;
+ main_thread_.message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&TextureLayerMailboxHolderTest::CreateImplRef,
+ base::Unretained(this),
+ &compositor1));
+
+ // Then the texture layer is removed and attached to compositor2, and passes a
+ // reference to its impl tree.
+ scoped_ptr<SingleReleaseCallback> compositor2;
+ main_thread_.message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&TextureLayerMailboxHolderTest::CreateImplRef,
+ base::Unretained(this),
+ &compositor2));
+
+ Wait(main_thread_);
+ Mock::VerifyAndClearExpectations(&test_data_.mock_callback_);
+
+ // The main thread reference is destroyed first.
+ main_thread_.message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&TextureLayerMailboxHolderTest::ReleaseMainRef,
+ base::Unretained(this)));
+
+ // One compositor destroys their impl tree.
+ compositor2->Run(200, false);
+
+ Wait(main_thread_);
+
+ EXPECT_CALL(test_data_.mock_callback_, Release(_, _, _)).Times(0);
+ Mock::VerifyAndClearExpectations(&test_data_.mock_callback_);
+
+ // The second impl reference is destroyed last, causing the mailbox to be
+ // released back to the embedder with the last sync point from the impl tree.
+ EXPECT_CALL(test_data_.mock_callback_,
+ Release(test_data_.mailbox_name1_, 100, true)).Times(1);
+
+ compositor1->Run(100, true);
+ Wait(main_thread_);
+ Mock::VerifyAndClearExpectations(&test_data_.mock_callback_);
+}
+
+TEST_F(TextureLayerMailboxHolderTest, TwoCompositors_SecondImplRefShortcut) {
+ scoped_refptr<TextureLayer> test_layer = TextureLayer::CreateForMailbox(NULL);
+ ASSERT_TRUE(test_layer.get());
+
+ main_thread_.message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&TextureLayerMailboxHolderTest::CreateMainRef,
+ base::Unretained(this)));
+
+ Wait(main_thread_);
+
+ // The texture layer is attached to compositor1, and passes a reference to its
+ // impl tree.
+ scoped_ptr<SingleReleaseCallback> compositor1;
+ main_thread_.message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&TextureLayerMailboxHolderTest::CreateImplRef,
+ base::Unretained(this),
+ &compositor1));
+
+ // Then the texture layer is removed and attached to compositor2, and passes a
+ // reference to its impl tree.
+ scoped_ptr<SingleReleaseCallback> compositor2;
+ main_thread_.message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&TextureLayerMailboxHolderTest::CreateImplRef,
+ base::Unretained(this),
+ &compositor2));
+
+ Wait(main_thread_);
+ Mock::VerifyAndClearExpectations(&test_data_.mock_callback_);
+
+ // The main thread reference is destroyed first.
+ main_thread_.message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&TextureLayerMailboxHolderTest::ReleaseMainRef,
+ base::Unretained(this)));
+
+ EXPECT_CALL(test_data_.mock_callback_,
+ Release(test_data_.mailbox_name1_, 200, true)).Times(1);
+
+ bool manual_reset = false;
+ bool initially_signaled = false;
+ base::WaitableEvent begin_capture(manual_reset, initially_signaled);
+ base::WaitableEvent wait_for_capture(manual_reset, initially_signaled);
+ base::WaitableEvent stop_capture(manual_reset, initially_signaled);
+
+ // Post a task to start capturing tasks on the main thread. This will block
+ // the main thread until we signal the |stop_capture| event.
+ main_thread_.message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&TextureLayerMailboxHolderTest::CapturePostTasksAndWait,
+ base::Unretained(this),
+ &begin_capture,
+ &wait_for_capture,
+ &stop_capture));
+
+ // Before the main thread capturing starts, one compositor destroys their
+ // impl reference. Since capturing did not start, this gets post-tasked to
+ // the main thread.
+ compositor1->Run(100, false);
+
+ // Start capturing on the main thread.
+ begin_capture.Signal();
+ wait_for_capture.Wait();
+
+ // Meanwhile, the second compositor released its impl reference, but this task
+ // gets shortcutted directly to the main thread. This means the reference is
+ // released before compositor1, whose reference will be released later when
+ // the post-task is serviced. But since it was destroyed _on the impl thread_
+ // last, its sync point values should be used.
+ compositor2->Run(200, true);
+
+ stop_capture.Signal();
+ Wait(main_thread_);
+
+ Mock::VerifyAndClearExpectations(&test_data_.mock_callback_);
}
class TextureLayerImplWithMailboxThreadedCallback : public LayerTreeTest {
@@ -432,21 +760,24 @@ class TextureLayerImplWithMailboxThreadedCallback : public LayerTreeTest {
// Make sure callback is received on main and doesn't block the impl thread.
void ReleaseCallback(unsigned sync_point, bool lost_resource) {
- EXPECT_EQ(true, proxy()->IsMainThread());
+ EXPECT_EQ(true, main_thread_.CalledOnValidThread());
EXPECT_FALSE(lost_resource);
++callback_count_;
}
void SetMailbox(char mailbox_char) {
- TextureMailbox mailbox(
- std::string(64, mailbox_char),
+ EXPECT_EQ(true, main_thread_.CalledOnValidThread());
+ TextureMailbox mailbox(std::string(64, mailbox_char));
+ scoped_ptr<SingleReleaseCallback> callback = SingleReleaseCallback::Create(
base::Bind(
&TextureLayerImplWithMailboxThreadedCallback::ReleaseCallback,
base::Unretained(this)));
- layer_->SetTextureMailbox(mailbox);
+ layer_->SetTextureMailbox(mailbox, callback.Pass());
}
virtual void BeginTest() OVERRIDE {
+ EXPECT_EQ(true, main_thread_.CalledOnValidThread());
+
gfx::Size bounds(100, 100);
root_ = Layer::Create();
root_->SetAnchorPoint(gfx::PointF());
@@ -481,61 +812,58 @@ class TextureLayerImplWithMailboxThreadedCallback : public LayerTreeTest {
EXPECT_EQ(1, callback_count_);
break;
case 2:
- // Old mailbox was released, task was posted, but won't execute
- // until this DidCommit returns.
- // TODO(piman): fix this.
- EXPECT_EQ(1, callback_count_);
- layer_tree_host()->SetNeedsCommit();
- break;
- case 3:
EXPECT_EQ(2, callback_count_);
// Case #3: change mailbox when the layer doesn't draw. The old
// mailbox should be released during the next commit.
layer_->SetBounds(gfx::Size());
SetMailbox('4');
break;
- case 4:
- // Old mailbox was released, task was posted, but won't execute
- // until this DidCommit returns.
- // TODO(piman): fix this.
- EXPECT_EQ(2, callback_count_);
- layer_tree_host()->SetNeedsCommit();
- break;
- case 5:
+ case 3:
EXPECT_EQ(3, callback_count_);
// Case #4: release mailbox that was committed but never drawn. The
// old mailbox should be released during the next commit.
- layer_->SetTextureMailbox(TextureMailbox());
- break;
- case 6:
- // Old mailbox was released, task was posted, but won't execute
- // until this DidCommit returns.
- // TODO(piman): fix this.
- EXPECT_EQ(3, callback_count_);
- layer_tree_host()->SetNeedsCommit();
+ layer_->SetTextureMailbox(TextureMailbox(),
+ scoped_ptr<SingleReleaseCallback>());
break;
- case 7:
+ case 4:
+ if (layer_tree_host()->settings().impl_side_painting) {
+ // With impl painting, the texture mailbox will still be on the impl
+ // thread when the commit finishes, because the layer is not drawble
+ // when it has no texture mailbox, and thus does not block the commit
+ // on activation. So, we wait for activation.
+ // TODO(danakj): fix this. crbug.com/277953
+ layer_tree_host()->SetNeedsCommit();
+ break;
+ } else {
+ ++commit_count_;
+ }
+ case 5:
EXPECT_EQ(4, callback_count_);
// Restore a mailbox for the next step.
SetMailbox('5');
break;
- case 8:
+ case 6:
// Case #5: remove layer from tree. Callback should *not* be called, the
// mailbox is returned to the main thread.
EXPECT_EQ(4, callback_count_);
layer_->RemoveFromParent();
break;
- case 9:
- // Mailbox was released to the main thread, task was posted, but won't
- // execute until this DidCommit returns.
- // TODO(piman): fix this.
- EXPECT_EQ(4, callback_count_);
- layer_tree_host()->SetNeedsCommit();
- break;
- case 10:
+ case 7:
+ if (layer_tree_host()->settings().impl_side_painting) {
+ // With impl painting, the texture mailbox will still be on the impl
+ // thread when the commit finishes, because the layer is not around to
+ // block the commit on activation anymore. So, we wait for activation.
+ // TODO(danakj): fix this. crbug.com/277953
+ layer_tree_host()->SetNeedsCommit();
+ break;
+ } else {
+ ++commit_count_;
+ }
+ case 8:
EXPECT_EQ(4, callback_count_);
// Resetting the mailbox will call the callback now.
- layer_->SetTextureMailbox(TextureMailbox());
+ layer_->SetTextureMailbox(TextureMailbox(),
+ scoped_ptr<SingleReleaseCallback>());
EXPECT_EQ(5, callback_count_);
EndTest();
break;
@@ -548,6 +876,7 @@ class TextureLayerImplWithMailboxThreadedCallback : public LayerTreeTest {
virtual void AfterTest() OVERRIDE {}
private:
+ base::ThreadChecker main_thread_;
int callback_count_;
int commit_count_;
scoped_refptr<Layer> root_;
@@ -557,6 +886,247 @@ class TextureLayerImplWithMailboxThreadedCallback : public LayerTreeTest {
SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F(
TextureLayerImplWithMailboxThreadedCallback);
+
+class TextureLayerNoMailboxIsActivatedDuringCommit : public LayerTreeTest,
+ public TextureLayerClient {
+ protected:
+ TextureLayerNoMailboxIsActivatedDuringCommit()
+ : wait_thread_("WAIT"),
+ wait_event_(false, false) {
+ wait_thread_.Start();
+ }
+
+ virtual void BeginTest() OVERRIDE {
+ activate_count_ = 0;
+
+ gfx::Size bounds(100, 100);
+ root_ = Layer::Create();
+ root_->SetAnchorPoint(gfx::PointF());
+ root_->SetBounds(bounds);
+
+ layer_ = TextureLayer::Create(this);
+ layer_->SetIsDrawable(true);
+ layer_->SetAnchorPoint(gfx::PointF());
+ layer_->SetBounds(bounds);
+
+ root_->AddChild(layer_);
+ layer_tree_host()->SetRootLayer(root_);
+ layer_tree_host()->SetViewportSize(bounds);
+
+ PostSetNeedsCommitToMainThread();
+ }
+
+ // TextureLayerClient implementation.
+ virtual unsigned PrepareTexture() OVERRIDE {
+ return OffscreenContextProviderForMainThread()
+ ->Context3d()->createTexture();
+ }
+ virtual WebKit::WebGraphicsContext3D* Context3d() OVERRIDE {
+ return OffscreenContextProviderForMainThread()->Context3d();
+ }
+ virtual bool PrepareTextureMailbox(
+ TextureMailbox* mailbox,
+ scoped_ptr<SingleReleaseCallback>* release_callback,
+ bool use_shared_memory) OVERRIDE {
+ return false;
+ }
+
+ virtual void WillActivateTreeOnThread(LayerTreeHostImpl* impl) OVERRIDE {
+ // Slow down activation so the main thread DidCommit() will run if
+ // not blocked.
+ wait_thread_.message_loop()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&base::WaitableEvent::Signal,
+ base::Unretained(&wait_event_)),
+ base::TimeDelta::FromMilliseconds(10));
+ wait_event_.Wait();
+
+ base::AutoLock lock(activate_lock_);
+ ++activate_count_;
+ }
+
+ virtual void DidActivateTreeOnThread(LayerTreeHostImpl* impl) OVERRIDE {
+ // The main thread is awake now, and will run DidCommit() immediately.
+ // Run DidActivate() afterwards by posting it now.
+ proxy()->MainThreadTaskRunner()->PostTask(
+ FROM_HERE,
+ base::Bind(&TextureLayerNoMailboxIsActivatedDuringCommit::DidActivate,
+ base::Unretained(this)));
+ }
+
+ void DidActivate() {
+ base::AutoLock lock(activate_lock_);
+ switch (activate_count_) {
+ case 1:
+ // The first texture has been activated. Invalidate the layer so it
+ // grabs a new texture id from the client.
+ layer_->SetNeedsDisplay();
+ // So this commit number should complete after the second activate.
+ EXPECT_EQ(1, layer_tree_host()->source_frame_number());
+ break;
+ case 2:
+ // The second mailbox has been activated. Remove the layer from
+ // the tree to cause another commit/activation. The commit should
+ // finish *after* the layer is removed from the active tree.
+ layer_->RemoveFromParent();
+ // So this commit number should complete after the third activate.
+ EXPECT_EQ(2, layer_tree_host()->source_frame_number());
+ break;
+ case 3:
+ EndTest();
+ break;
+ }
+ }
+
+ virtual void DidCommit() OVERRIDE {
+ switch (layer_tree_host()->source_frame_number()) {
+ case 2: {
+ // The activate for the 2nd texture should have happened before now.
+ base::AutoLock lock(activate_lock_);
+ EXPECT_EQ(2, activate_count_);
+ break;
+ }
+ case 3: {
+ // The activate to remove the layer should have happened before now.
+ base::AutoLock lock(activate_lock_);
+ EXPECT_EQ(3, activate_count_);
+ break;
+ }
+ }
+ }
+
+
+ virtual void AfterTest() OVERRIDE {}
+
+ base::Thread wait_thread_;
+ base::WaitableEvent wait_event_;
+ base::Lock activate_lock_;
+ int activate_count_;
+ int activate_commit_;
+ scoped_refptr<Layer> root_;
+ scoped_refptr<TextureLayer> layer_;
+};
+
+SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F(
+ TextureLayerNoMailboxIsActivatedDuringCommit);
+
+class TextureLayerMailboxIsActivatedDuringCommit : public LayerTreeTest {
+ protected:
+ TextureLayerMailboxIsActivatedDuringCommit()
+ : wait_thread_("WAIT"),
+ wait_event_(false, false) {
+ wait_thread_.Start();
+ }
+
+ static void ReleaseCallback(unsigned sync_point, bool lost_resource) {}
+
+ void SetMailbox(char mailbox_char) {
+ TextureMailbox mailbox(std::string(64, mailbox_char));
+ scoped_ptr<SingleReleaseCallback> callback = SingleReleaseCallback::Create(
+ base::Bind(
+ &TextureLayerMailboxIsActivatedDuringCommit::ReleaseCallback));
+ layer_->SetTextureMailbox(mailbox, callback.Pass());
+ }
+
+ virtual void BeginTest() OVERRIDE {
+ activate_count_ = 0;
+
+ gfx::Size bounds(100, 100);
+ root_ = Layer::Create();
+ root_->SetAnchorPoint(gfx::PointF());
+ root_->SetBounds(bounds);
+
+ layer_ = TextureLayer::CreateForMailbox(NULL);
+ layer_->SetIsDrawable(true);
+ layer_->SetAnchorPoint(gfx::PointF());
+ layer_->SetBounds(bounds);
+
+ root_->AddChild(layer_);
+ layer_tree_host()->SetRootLayer(root_);
+ layer_tree_host()->SetViewportSize(bounds);
+ SetMailbox('1');
+
+ PostSetNeedsCommitToMainThread();
+ }
+
+ virtual void WillActivateTreeOnThread(LayerTreeHostImpl* impl) OVERRIDE {
+ // Slow down activation so the main thread DidCommit() will run if
+ // not blocked.
+ wait_thread_.message_loop()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&base::WaitableEvent::Signal,
+ base::Unretained(&wait_event_)),
+ base::TimeDelta::FromMilliseconds(10));
+ wait_event_.Wait();
+
+ base::AutoLock lock(activate_lock_);
+ ++activate_count_;
+ }
+
+ virtual void DidActivateTreeOnThread(LayerTreeHostImpl* impl) OVERRIDE {
+ // The main thread is awake now, and will run DidCommit() immediately.
+ // Run DidActivate() afterwards by posting it now.
+ proxy()->MainThreadTaskRunner()->PostTask(
+ FROM_HERE,
+ base::Bind(&TextureLayerMailboxIsActivatedDuringCommit::DidActivate,
+ base::Unretained(this)));
+ }
+
+ void DidActivate() {
+ base::AutoLock lock(activate_lock_);
+ switch (activate_count_) {
+ case 1:
+ // The first mailbox has been activated. Set a new mailbox, and
+ // expect the next commit to finish *after* it is activated.
+ SetMailbox('2');
+ // So this commit number should complete after the second activate.
+ EXPECT_EQ(1, layer_tree_host()->source_frame_number());
+ break;
+ case 2:
+ // The second mailbox has been activated. Remove the layer from
+ // the tree to cause another commit/activation. The commit should
+ // finish *after* the layer is removed from the active tree.
+ layer_->RemoveFromParent();
+ // So this commit number should complete after the third activate.
+ EXPECT_EQ(2, layer_tree_host()->source_frame_number());
+ break;
+ case 3:
+ EndTest();
+ break;
+ }
+ }
+
+ virtual void DidCommit() OVERRIDE {
+ switch (layer_tree_host()->source_frame_number()) {
+ case 2: {
+ // The activate for the 2nd mailbox should have happened before now.
+ base::AutoLock lock(activate_lock_);
+ EXPECT_EQ(2, activate_count_);
+ break;
+ }
+ case 3: {
+ // The activate to remove the layer should have happened before now.
+ base::AutoLock lock(activate_lock_);
+ EXPECT_EQ(3, activate_count_);
+ break;
+ }
+ }
+ }
+
+
+ virtual void AfterTest() OVERRIDE {}
+
+ base::Thread wait_thread_;
+ base::WaitableEvent wait_event_;
+ base::Lock activate_lock_;
+ int activate_count_;
+ scoped_refptr<Layer> root_;
+ scoped_refptr<TextureLayer> layer_;
+};
+
+SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F(
+ TextureLayerMailboxIsActivatedDuringCommit);
+
class TextureLayerImplWithMailboxTest : public TextureLayerTest {
protected:
TextureLayerImplWithMailboxTest()
@@ -596,14 +1166,17 @@ TEST_F(TextureLayerImplWithMailboxTest, TestWillDraw) {
{
scoped_ptr<TextureLayerImpl> impl_layer =
TextureLayerImpl::Create(host_impl_.active_tree(), 1, true);
- impl_layer->SetTextureMailbox(test_data_.mailbox1_);
+ impl_layer->SetTextureMailbox(
+ test_data_.mailbox1_,
+ SingleReleaseCallback::Create(test_data_.release_mailbox1_));
EXPECT_TRUE(WillDraw(impl_layer.get(), DRAW_MODE_HARDWARE));
}
{
scoped_ptr<TextureLayerImpl> impl_layer =
TextureLayerImpl::Create(host_impl_.active_tree(), 1, true);
- impl_layer->SetTextureMailbox(TextureMailbox());
+ impl_layer->SetTextureMailbox(TextureMailbox(),
+ scoped_ptr<SingleReleaseCallback>());
EXPECT_FALSE(WillDraw(impl_layer.get(), DRAW_MODE_HARDWARE));
}
@@ -611,15 +1184,19 @@ TEST_F(TextureLayerImplWithMailboxTest, TestWillDraw) {
// Software resource.
scoped_ptr<TextureLayerImpl> impl_layer =
TextureLayerImpl::Create(host_impl_.active_tree(), 1, true);
- impl_layer->SetTextureMailbox(test_data_.mailbox3_);
+ impl_layer->SetTextureMailbox(
+ test_data_.mailbox3_,
+ SingleReleaseCallback::Create(test_data_.release_mailbox3_));
EXPECT_TRUE(WillDraw(impl_layer.get(), DRAW_MODE_HARDWARE));
}
{
scoped_ptr<TextureLayerImpl> impl_layer =
TextureLayerImpl::Create(host_impl_.active_tree(), 1, false);
+ ContextProvider* context_provider =
+ host_impl_.output_surface()->context_provider();
unsigned texture =
- host_impl_.output_surface()->context3d()->createTexture();
+ context_provider->Context3d()->createTexture();
impl_layer->set_texture_id(texture);
EXPECT_TRUE(WillDraw(impl_layer.get(), DRAW_MODE_HARDWARE));
}
@@ -635,14 +1212,17 @@ TEST_F(TextureLayerImplWithMailboxTest, TestWillDraw) {
{
scoped_ptr<TextureLayerImpl> impl_layer =
TextureLayerImpl::Create(host_impl_.active_tree(), 1, true);
- impl_layer->SetTextureMailbox(test_data_.mailbox1_);
+ impl_layer->SetTextureMailbox(
+ test_data_.mailbox1_,
+ SingleReleaseCallback::Create(test_data_.release_mailbox1_));
EXPECT_FALSE(WillDraw(impl_layer.get(), DRAW_MODE_SOFTWARE));
}
{
scoped_ptr<TextureLayerImpl> impl_layer =
TextureLayerImpl::Create(host_impl_.active_tree(), 1, true);
- impl_layer->SetTextureMailbox(TextureMailbox());
+ impl_layer->SetTextureMailbox(TextureMailbox(),
+ scoped_ptr<SingleReleaseCallback>());
EXPECT_FALSE(WillDraw(impl_layer.get(), DRAW_MODE_SOFTWARE));
}
@@ -650,15 +1230,19 @@ TEST_F(TextureLayerImplWithMailboxTest, TestWillDraw) {
// Software resource.
scoped_ptr<TextureLayerImpl> impl_layer =
TextureLayerImpl::Create(host_impl_.active_tree(), 1, true);
- impl_layer->SetTextureMailbox(test_data_.mailbox3_);
+ impl_layer->SetTextureMailbox(
+ test_data_.mailbox3_,
+ SingleReleaseCallback::Create(test_data_.release_mailbox3_));
EXPECT_TRUE(WillDraw(impl_layer.get(), DRAW_MODE_SOFTWARE));
}
{
scoped_ptr<TextureLayerImpl> impl_layer =
TextureLayerImpl::Create(host_impl_.active_tree(), 1, false);
+ ContextProvider* context_provider =
+ host_impl_.output_surface()->context_provider();
unsigned texture =
- host_impl_.output_surface()->context3d()->createTexture();
+ context_provider->Context3d()->createTexture();
impl_layer->set_texture_id(texture);
EXPECT_FALSE(WillDraw(impl_layer.get(), DRAW_MODE_SOFTWARE));
}
@@ -674,15 +1258,19 @@ TEST_F(TextureLayerImplWithMailboxTest, TestWillDraw) {
{
scoped_ptr<TextureLayerImpl> impl_layer =
TextureLayerImpl::Create(host_impl_.active_tree(), 1, true);
- impl_layer->SetTextureMailbox(test_data_.mailbox1_);
+ impl_layer->SetTextureMailbox(
+ test_data_.mailbox1_,
+ SingleReleaseCallback::Create(test_data_.release_mailbox1_));
EXPECT_FALSE(WillDraw(impl_layer.get(), DRAW_MODE_RESOURCELESS_SOFTWARE));
}
{
scoped_ptr<TextureLayerImpl> impl_layer =
TextureLayerImpl::Create(host_impl_.active_tree(), 1, false);
+ ContextProvider* context_provider =
+ host_impl_.output_surface()->context_provider();
unsigned texture =
- host_impl_.output_surface()->context3d()->createTexture();
+ context_provider->Context3d()->createTexture();
impl_layer->set_texture_id(texture);
EXPECT_FALSE(WillDraw(impl_layer.get(), DRAW_MODE_RESOURCELESS_SOFTWARE));
}
@@ -698,7 +1286,9 @@ TEST_F(TextureLayerImplWithMailboxTest, TestImplLayerCallbacks) {
pending_layer->CreateLayerImpl(host_impl_.active_tree()));
ASSERT_TRUE(active_layer);
- pending_layer->SetTextureMailbox(test_data_.mailbox1_);
+ pending_layer->SetTextureMailbox(
+ test_data_.mailbox1_,
+ SingleReleaseCallback::Create(test_data_.release_mailbox1_));
// Test multiple commits without an activation.
EXPECT_CALL(test_data_.mock_callback_,
@@ -706,7 +1296,9 @@ TEST_F(TextureLayerImplWithMailboxTest, TestImplLayerCallbacks) {
test_data_.sync_point1_,
false))
.Times(1);
- pending_layer->SetTextureMailbox(test_data_.mailbox2_);
+ pending_layer->SetTextureMailbox(
+ test_data_.mailbox2_,
+ SingleReleaseCallback::Create(test_data_.release_mailbox2_));
Mock::VerifyAndClearExpectations(&test_data_.mock_callback_);
// Test callback after activation.
@@ -714,7 +1306,9 @@ TEST_F(TextureLayerImplWithMailboxTest, TestImplLayerCallbacks) {
active_layer->DidBecomeActive();
EXPECT_CALL(test_data_.mock_callback_, Release(_, _, _)).Times(0);
- pending_layer->SetTextureMailbox(test_data_.mailbox1_);
+ pending_layer->SetTextureMailbox(
+ test_data_.mailbox1_,
+ SingleReleaseCallback::Create(test_data_.release_mailbox1_));
Mock::VerifyAndClearExpectations(&test_data_.mock_callback_);
EXPECT_CALL(test_data_.mock_callback_,
@@ -728,7 +1322,8 @@ TEST_F(TextureLayerImplWithMailboxTest, TestImplLayerCallbacks) {
EXPECT_CALL(test_data_.mock_callback_,
Release(test_data_.mailbox_name1_, _, false))
.Times(1);
- pending_layer->SetTextureMailbox(TextureMailbox());
+ pending_layer->SetTextureMailbox(TextureMailbox(),
+ scoped_ptr<SingleReleaseCallback>());
pending_layer->PushPropertiesTo(active_layer.get());
active_layer->DidBecomeActive();
Mock::VerifyAndClearExpectations(&test_data_.mock_callback_);
@@ -739,7 +1334,9 @@ TEST_F(TextureLayerImplWithMailboxTest, TestImplLayerCallbacks) {
test_data_.sync_point1_,
false))
.Times(1);
- pending_layer->SetTextureMailbox(test_data_.mailbox1_);
+ pending_layer->SetTextureMailbox(
+ test_data_.mailbox1_,
+ SingleReleaseCallback::Create(test_data_.release_mailbox1_));
}
TEST_F(TextureLayerImplWithMailboxTest,
@@ -751,18 +1348,23 @@ TEST_F(TextureLayerImplWithMailboxTest,
EXPECT_CALL(test_data_.mock_callback_,
Release(test_data_.mailbox_name1_, _, false))
.Times(1);
- impl_layer->SetTextureMailbox(test_data_.mailbox1_);
+ impl_layer->SetTextureMailbox(
+ test_data_.mailbox1_,
+ SingleReleaseCallback::Create(test_data_.release_mailbox1_));
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->SetTextureMailbox(TextureMailbox());
+ impl_layer->SetTextureMailbox(TextureMailbox(),
+ scoped_ptr<SingleReleaseCallback>());
}
TEST_F(TextureLayerImplWithMailboxTest, TestCallbackOnInUseResource) {
ResourceProvider* provider = host_impl_.active_tree()->resource_provider();
ResourceProvider::ResourceId id =
- provider->CreateResourceFromTextureMailbox(test_data_.mailbox1_);
+ provider->CreateResourceFromTextureMailbox(
+ test_data_.mailbox1_,
+ SingleReleaseCallback::Create(test_data_.release_mailbox1_));
provider->AllocateForTesting(id);
// Transfer some resources to the parent.
@@ -777,7 +1379,9 @@ TEST_F(TextureLayerImplWithMailboxTest, TestCallbackOnInUseResource) {
EXPECT_CALL(test_data_.mock_callback_,
Release(test_data_.mailbox_name1_, _, false))
.Times(1);
- provider->ReceiveFromParent(list);
+ ReturnedResourceArray returned;
+ TransferableResource::ReturnResources(list, &returned);
+ provider->ReceiveReturnsFromParent(returned);
}
// Check that ClearClient correctly clears the state so that the impl side
@@ -799,8 +1403,7 @@ class TextureLayerClientTest
TestWebGraphicsContext3D::Create());
context_ = context.get();
texture_ = context->createTexture();
- return FakeOutputSurface::Create3d(
- context.PassAs<WebKit::WebGraphicsContext3D>()).PassAs<OutputSurface>();
+ return FakeOutputSurface::Create3d(context.Pass()).PassAs<OutputSurface>();
}
virtual unsigned PrepareTexture() OVERRIDE {
@@ -812,7 +1415,9 @@ class TextureLayerClientTest
}
virtual bool PrepareTextureMailbox(
- cc::TextureMailbox* mailbox, bool use_shared_memory) OVERRIDE {
+ TextureMailbox* mailbox,
+ scoped_ptr<SingleReleaseCallback>* release_callback,
+ bool use_shared_memory) OVERRIDE {
return false;
}
@@ -899,6 +1504,343 @@ class TextureLayerClientTest
// renderer.
SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F(TextureLayerClientTest);
+
+// Checks that changing a texture in the client for a TextureLayer that's
+// invisible correctly works without drawing a deleted texture. See
+// crbug.com/266628
+class TextureLayerChangeInvisibleTest
+ : public LayerTreeTest,
+ public TextureLayerClient {
+ public:
+ TextureLayerChangeInvisibleTest()
+ : client_context_(TestWebGraphicsContext3D::Create()),
+ texture_(client_context_->createTexture()),
+ texture_to_delete_on_next_commit_(0),
+ prepare_called_(0),
+ commit_count_(0),
+ expected_texture_on_draw_(0) {}
+
+ // TextureLayerClient implementation.
+ virtual unsigned PrepareTexture() OVERRIDE {
+ ++prepare_called_;
+ return texture_;
+ }
+
+ // TextureLayerClient implementation.
+ virtual WebKit::WebGraphicsContext3D* Context3d() OVERRIDE {
+ return client_context_.get();
+ }
+
+ // TextureLayerClient implementation.
+ virtual bool PrepareTextureMailbox(
+ cc::TextureMailbox* mailbox,
+ scoped_ptr<SingleReleaseCallback>* release_callback,
+ bool use_shared_memory) OVERRIDE {
+ return false;
+ }
+
+ virtual void SetupTree() OVERRIDE {
+ scoped_refptr<Layer> root = Layer::Create();
+ root->SetBounds(gfx::Size(10, 10));
+ root->SetAnchorPoint(gfx::PointF());
+ root->SetIsDrawable(true);
+
+ solid_layer_ = SolidColorLayer::Create();
+ solid_layer_->SetBounds(gfx::Size(10, 10));
+ solid_layer_->SetIsDrawable(true);
+ solid_layer_->SetBackgroundColor(SK_ColorWHITE);
+ 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_->SetAnchorPoint(gfx::PointF());
+ texture_layer_->SetIsDrawable(true);
+ parent_layer_->AddChild(texture_layer_);
+
+ layer_tree_host()->SetRootLayer(root);
+ LayerTreeTest::SetupTree();
+ }
+
+ virtual void BeginTest() OVERRIDE {
+ PostSetNeedsCommitToMainThread();
+ }
+
+ virtual void DidCommitAndDrawFrame() OVERRIDE {
+ ++commit_count_;
+ switch (commit_count_) {
+ case 1:
+ // We should have updated the layer, committing the texture.
+ EXPECT_EQ(1, prepare_called_);
+ // Make layer invisible.
+ parent_layer_->SetOpacity(0.f);
+ break;
+ case 2: {
+ // Layer shouldn't have been updated.
+ EXPECT_EQ(1, prepare_called_);
+ // Change the texture.
+ texture_to_delete_on_next_commit_ = texture_;
+ texture_ = client_context_->createTexture();
+ texture_layer_->SetNeedsDisplay();
+ // Force a change to make sure we draw a frame.
+ solid_layer_->SetBackgroundColor(SK_ColorGRAY);
+ break;
+ }
+ case 3:
+ EXPECT_EQ(1, prepare_called_);
+ client_context_->deleteTexture(texture_to_delete_on_next_commit_);
+ texture_to_delete_on_next_commit_ = 0;
+ // Make layer visible again.
+ parent_layer_->SetOpacity(1.f);
+ break;
+ case 4: {
+ // Layer should have been updated.
+ EXPECT_EQ(2, prepare_called_);
+ texture_layer_->ClearClient();
+ client_context_->deleteTexture(texture_);
+ texture_ = 0;
+ break;
+ }
+ case 5:
+ EndTest();
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+ }
+
+ virtual void BeginCommitOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
+ ASSERT_TRUE(proxy()->IsMainThreadBlocked());
+ // This is the only texture that can be drawn this frame.
+ expected_texture_on_draw_ = texture_;
+ }
+
+ virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
+ LayerTreeHostImpl::FrameData* frame_data,
+ bool result) OVERRIDE {
+ ContextForImplThread(host_impl)->ResetUsedTextures();
+ return true;
+ }
+
+ virtual void SwapBuffersOnThread(LayerTreeHostImpl* host_impl,
+ bool result) OVERRIDE {
+ ASSERT_TRUE(result);
+ TestWebGraphicsContext3D* context = ContextForImplThread(host_impl);
+ int used_textures = context->NumUsedTextures();
+ switch (host_impl->active_tree()->source_frame_number()) {
+ case 0:
+ EXPECT_EQ(1, used_textures);
+ EXPECT_TRUE(context->UsedTexture(expected_texture_on_draw_));
+ break;
+ case 1:
+ case 2:
+ EXPECT_EQ(0, used_textures);
+ break;
+ case 3:
+ EXPECT_EQ(1, used_textures);
+ EXPECT_TRUE(context->UsedTexture(expected_texture_on_draw_));
+ break;
+ default:
+ break;
+ }
+ }
+
+ virtual void AfterTest() OVERRIDE {}
+
+ private:
+ TestWebGraphicsContext3D* ContextForImplThread(LayerTreeHostImpl* host_impl) {
+ return static_cast<TestWebGraphicsContext3D*>(
+ host_impl->output_surface()->context_provider()->Context3d());
+ }
+
+ scoped_refptr<SolidColorLayer> solid_layer_;
+ scoped_refptr<Layer> parent_layer_;
+ scoped_refptr<TextureLayer> texture_layer_;
+ scoped_ptr<TestWebGraphicsContext3D> client_context_;
+
+ // Used on the main thread, and on the impl thread while the main thread is
+ // blocked.
+ unsigned texture_;
+
+ // Used on the main thread.
+ unsigned texture_to_delete_on_next_commit_;
+ int prepare_called_;
+ int commit_count_;
+
+ // Used on the compositor thread.
+ unsigned expected_texture_on_draw_;
+};
+
+// The TextureLayerChangeInvisibleTest does not use mailboxes, so can't use a
+// delegating renderer.
+SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F(TextureLayerChangeInvisibleTest);
+
+// Checks that changing a mailbox in the client for a TextureLayer that's
+// invisible correctly works and uses the new mailbox as soon as the layer
+// becomes visible (and returns the old one).
+class TextureLayerChangeInvisibleMailboxTest
+ : public LayerTreeTest,
+ public TextureLayerClient {
+ public:
+ TextureLayerChangeInvisibleMailboxTest()
+ : mailbox_changed_(true),
+ mailbox_returned_(0),
+ prepare_called_(0),
+ commit_count_(0) {
+ mailbox_ = MakeMailbox('1');
+ }
+
+ // TextureLayerClient implementation.
+ virtual unsigned PrepareTexture() OVERRIDE {
+ NOTREACHED();
+ return 0;
+ }
+
+ // TextureLayerClient implementation.
+ virtual WebKit::WebGraphicsContext3D* Context3d() OVERRIDE {
+ NOTREACHED();
+ return NULL;
+ }
+
+ // TextureLayerClient implementation.
+ virtual bool PrepareTextureMailbox(
+ cc::TextureMailbox* mailbox,
+ scoped_ptr<SingleReleaseCallback>* release_callback,
+ bool use_shared_memory) OVERRIDE {
+ ++prepare_called_;
+ if (!mailbox_changed_)
+ return false;
+ *mailbox = mailbox_;
+ *release_callback = SingleReleaseCallback::Create(
+ base::Bind(&TextureLayerChangeInvisibleMailboxTest::MailboxReleased,
+ base::Unretained(this)));
+ return true;
+ }
+
+ TextureMailbox MakeMailbox(char name) {
+ return TextureMailbox(std::string(64, name));
+ }
+
+ void MailboxReleased(unsigned sync_point, bool lost_resource) {
+ ++mailbox_returned_;
+ }
+
+ virtual void SetupTree() OVERRIDE {
+ scoped_refptr<Layer> root = Layer::Create();
+ root->SetBounds(gfx::Size(10, 10));
+ root->SetAnchorPoint(gfx::PointF());
+ root->SetIsDrawable(true);
+
+ solid_layer_ = SolidColorLayer::Create();
+ solid_layer_->SetBounds(gfx::Size(10, 10));
+ solid_layer_->SetIsDrawable(true);
+ solid_layer_->SetBackgroundColor(SK_ColorWHITE);
+ 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::CreateForMailbox(this);
+ texture_layer_->SetBounds(gfx::Size(10, 10));
+ texture_layer_->SetAnchorPoint(gfx::PointF());
+ texture_layer_->SetIsDrawable(true);
+ parent_layer_->AddChild(texture_layer_);
+
+ layer_tree_host()->SetRootLayer(root);
+ LayerTreeTest::SetupTree();
+ }
+
+ virtual void BeginTest() OVERRIDE {
+ PostSetNeedsCommitToMainThread();
+ }
+
+ virtual void DidCommitAndDrawFrame() OVERRIDE {
+ ++commit_count_;
+ switch (commit_count_) {
+ case 1:
+ // We should have updated the layer, committing the texture.
+ EXPECT_EQ(1, prepare_called_);
+ // Make layer invisible.
+ parent_layer_->SetOpacity(0.f);
+ break;
+ case 2:
+ // Layer shouldn't have been updated.
+ EXPECT_EQ(1, prepare_called_);
+ // Change the texture.
+ mailbox_ = MakeMailbox('2');
+ mailbox_changed_ = true;
+ texture_layer_->SetNeedsDisplay();
+ // Force a change to make sure we draw a frame.
+ solid_layer_->SetBackgroundColor(SK_ColorGRAY);
+ break;
+ case 3:
+ // Layer shouldn't have been updated.
+ EXPECT_EQ(1, prepare_called_);
+ // So the old mailbox isn't returned yet.
+ EXPECT_EQ(0, mailbox_returned_);
+ // Make layer visible again.
+ parent_layer_->SetOpacity(1.f);
+ break;
+ case 4:
+ // Layer should have been updated.
+ EXPECT_EQ(2, prepare_called_);
+ // So the old mailbox should have been returned already.
+ EXPECT_EQ(1, mailbox_returned_);
+ texture_layer_->ClearClient();
+ break;
+ case 5:
+ EXPECT_EQ(2, mailbox_returned_);
+ EndTest();
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+ }
+
+ virtual void SwapBuffersOnThread(LayerTreeHostImpl* host_impl,
+ bool result) OVERRIDE {
+ ASSERT_TRUE(result);
+ DelegatedFrameData* delegated_frame_data =
+ output_surface()->last_sent_frame().delegated_frame_data.get();
+ if (!delegated_frame_data)
+ return;
+
+ // Return all resources immediately.
+ TransferableResourceArray resources_to_return =
+ output_surface()->resources_held_by_parent();
+
+ CompositorFrameAck ack;
+ for (size_t i = 0; i < resources_to_return.size(); ++i)
+ output_surface()->ReturnResource(resources_to_return[i].id, &ack);
+ host_impl->ReclaimResources(&ack);
+ host_impl->OnSwapBuffersComplete();
+ }
+
+ virtual void AfterTest() OVERRIDE {}
+
+ private:
+ scoped_refptr<SolidColorLayer> solid_layer_;
+ scoped_refptr<Layer> parent_layer_;
+ scoped_refptr<TextureLayer> texture_layer_;
+
+ // Used on the main thread.
+ bool mailbox_changed_;
+ TextureMailbox mailbox_;
+ int mailbox_returned_;
+ int prepare_called_;
+ int commit_count_;
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(TextureLayerChangeInvisibleMailboxTest);
+
// Test recovering from a lost context.
class TextureLayerLostContextTest
: public LayerTreeTest,
@@ -928,7 +1870,9 @@ class TextureLayerLostContextTest
}
virtual bool PrepareTextureMailbox(
- cc::TextureMailbox* mailbox, bool use_shared_memory) OVERRIDE {
+ TextureMailbox* mailbox,
+ scoped_ptr<SingleReleaseCallback>* release_callback,
+ bool use_shared_memory) OVERRIDE {
return false;
}
@@ -981,19 +1925,20 @@ SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F(TextureLayerLostContextTest);
class TextureLayerWithMailboxMainThreadDeleted : public LayerTreeTest {
public:
void ReleaseCallback(unsigned sync_point, bool lost_resource) {
- EXPECT_EQ(true, proxy()->IsMainThread());
+ EXPECT_EQ(true, main_thread_.CalledOnValidThread());
EXPECT_FALSE(lost_resource);
++callback_count_;
EndTest();
}
void SetMailbox(char mailbox_char) {
- TextureMailbox mailbox(
- std::string(64, mailbox_char),
+ EXPECT_EQ(true, main_thread_.CalledOnValidThread());
+ TextureMailbox mailbox(std::string(64, mailbox_char));
+ scoped_ptr<SingleReleaseCallback> callback = SingleReleaseCallback::Create(
base::Bind(
&TextureLayerWithMailboxMainThreadDeleted::ReleaseCallback,
base::Unretained(this)));
- layer_->SetTextureMailbox(mailbox);
+ layer_->SetTextureMailbox(mailbox, callback.Pass());
}
virtual void SetupTree() OVERRIDE {
@@ -1013,6 +1958,8 @@ class TextureLayerWithMailboxMainThreadDeleted : public LayerTreeTest {
}
virtual void BeginTest() OVERRIDE {
+ EXPECT_EQ(true, main_thread_.CalledOnValidThread());
+
callback_count_ = 0;
// Set the mailbox on the main thread.
@@ -1038,6 +1985,7 @@ class TextureLayerWithMailboxMainThreadDeleted : public LayerTreeTest {
}
private:
+ base::ThreadChecker main_thread_;
int callback_count_;
scoped_refptr<Layer> root_;
scoped_refptr<TextureLayer> layer_;
@@ -1049,19 +1997,20 @@ SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F(
class TextureLayerWithMailboxImplThreadDeleted : public LayerTreeTest {
public:
void ReleaseCallback(unsigned sync_point, bool lost_resource) {
- EXPECT_EQ(true, proxy()->IsMainThread());
+ EXPECT_EQ(true, main_thread_.CalledOnValidThread());
EXPECT_FALSE(lost_resource);
++callback_count_;
EndTest();
}
void SetMailbox(char mailbox_char) {
- TextureMailbox mailbox(
- std::string(64, mailbox_char),
+ EXPECT_EQ(true, main_thread_.CalledOnValidThread());
+ TextureMailbox mailbox(std::string(64, mailbox_char));
+ scoped_ptr<SingleReleaseCallback> callback = SingleReleaseCallback::Create(
base::Bind(
&TextureLayerWithMailboxImplThreadDeleted::ReleaseCallback,
base::Unretained(this)));
- layer_->SetTextureMailbox(mailbox);
+ layer_->SetTextureMailbox(mailbox, callback.Pass());
}
virtual void SetupTree() OVERRIDE {
@@ -1081,6 +2030,8 @@ class TextureLayerWithMailboxImplThreadDeleted : public LayerTreeTest {
}
virtual void BeginTest() OVERRIDE {
+ EXPECT_EQ(true, main_thread_.CalledOnValidThread());
+
callback_count_ = 0;
// Set the mailbox on the main thread.
@@ -1109,6 +2060,7 @@ class TextureLayerWithMailboxImplThreadDeleted : public LayerTreeTest {
}
private:
+ base::ThreadChecker main_thread_;
int callback_count_;
scoped_refptr<Layer> root_;
scoped_refptr<TextureLayer> layer_;