1// Copyright 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "cc/layers/texture_layer.h"
6
7#include <string>
8
9#include "base/callback.h"
10#include "cc/layers/texture_layer_client.h"
11#include "cc/layers/texture_layer_impl.h"
12#include "cc/test/fake_impl_proxy.h"
13#include "cc/test/fake_layer_tree_host_client.h"
14#include "cc/test/fake_layer_tree_host_impl.h"
15#include "cc/test/layer_test_common.h"
16#include "cc/test/layer_tree_test.h"
17#include "cc/trees/layer_tree_host.h"
18#include "cc/trees/layer_tree_impl.h"
19#include "cc/trees/single_thread_proxy.h"
20#include "gpu/GLES2/gl2extchromium.h"
21#include "testing/gmock/include/gmock/gmock.h"
22#include "testing/gtest/include/gtest/gtest.h"
23
24using ::testing::Mock;
25using ::testing::_;
26using ::testing::AtLeast;
27using ::testing::AnyNumber;
28
29namespace cc {
30namespace {
31
32class MockLayerTreeHost : public LayerTreeHost {
33 public:
34  explicit MockLayerTreeHost(LayerTreeHostClient* client)
35      : LayerTreeHost(client, LayerTreeSettings()) {
36    Initialize(NULL);
37  }
38
39  MOCK_METHOD0(AcquireLayerTextures, void());
40  MOCK_METHOD0(SetNeedsCommit, void());
41  MOCK_METHOD0(SetNeedsUpdateLayers, void());
42  MOCK_METHOD1(StartRateLimiter, void(WebKit::WebGraphicsContext3D* context));
43  MOCK_METHOD1(StopRateLimiter, void(WebKit::WebGraphicsContext3D* context));
44};
45
46class TextureLayerTest : public testing::Test {
47 public:
48  TextureLayerTest()
49      : fake_client_(
50          FakeLayerTreeHostClient(FakeLayerTreeHostClient::DIRECT_3D)),
51        host_impl_(&proxy_) {}
52
53 protected:
54  virtual void SetUp() {
55    layer_tree_host_.reset(new MockLayerTreeHost(&fake_client_));
56  }
57
58  virtual void TearDown() {
59    Mock::VerifyAndClearExpectations(layer_tree_host_.get());
60    EXPECT_CALL(*layer_tree_host_, AcquireLayerTextures()).Times(AnyNumber());
61    EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AnyNumber());
62
63    layer_tree_host_->SetRootLayer(NULL);
64    layer_tree_host_.reset();
65  }
66
67  scoped_ptr<MockLayerTreeHost> layer_tree_host_;
68  FakeImplProxy proxy_;
69  FakeLayerTreeHostClient fake_client_;
70  FakeLayerTreeHostImpl host_impl_;
71};
72
73TEST_F(TextureLayerTest, SyncImplWhenChangingTextureId) {
74  scoped_refptr<TextureLayer> test_layer = TextureLayer::Create(NULL);
75  ASSERT_TRUE(test_layer.get());
76
77  EXPECT_CALL(*layer_tree_host_, AcquireLayerTextures()).Times(AnyNumber());
78  EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AnyNumber());
79  layer_tree_host_->SetRootLayer(test_layer);
80  Mock::VerifyAndClearExpectations(layer_tree_host_.get());
81  EXPECT_EQ(test_layer->layer_tree_host(), layer_tree_host_.get());
82
83  EXPECT_CALL(*layer_tree_host_, AcquireLayerTextures()).Times(0);
84  EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AtLeast(1));
85  test_layer->SetTextureId(1);
86  Mock::VerifyAndClearExpectations(layer_tree_host_.get());
87
88  EXPECT_CALL(*layer_tree_host_, AcquireLayerTextures()).Times(AtLeast(1));
89  EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AtLeast(1));
90  test_layer->SetTextureId(2);
91  Mock::VerifyAndClearExpectations(layer_tree_host_.get());
92
93  EXPECT_CALL(*layer_tree_host_, AcquireLayerTextures()).Times(AtLeast(1));
94  EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AtLeast(1));
95  test_layer->SetTextureId(0);
96  Mock::VerifyAndClearExpectations(layer_tree_host_.get());
97}
98
99TEST_F(TextureLayerTest, SyncImplWhenDrawing) {
100  gfx::RectF dirty_rect(0.f, 0.f, 1.f, 1.f);
101
102  scoped_refptr<TextureLayer> test_layer = TextureLayer::Create(NULL);
103  ASSERT_TRUE(test_layer.get());
104  scoped_ptr<TextureLayerImpl> impl_layer;
105  impl_layer = TextureLayerImpl::Create(host_impl_.active_tree(), 1, false);
106  ASSERT_TRUE(impl_layer);
107
108  EXPECT_CALL(*layer_tree_host_, AcquireLayerTextures()).Times(AnyNumber());
109  EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AnyNumber());
110  layer_tree_host_->SetRootLayer(test_layer);
111  test_layer->SetTextureId(1);
112  test_layer->SetIsDrawable(true);
113  Mock::VerifyAndClearExpectations(layer_tree_host_.get());
114  EXPECT_EQ(test_layer->layer_tree_host(), layer_tree_host_.get());
115
116  EXPECT_CALL(*layer_tree_host_, AcquireLayerTextures()).Times(1);
117  EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(0);
118  test_layer->WillModifyTexture();
119  Mock::VerifyAndClearExpectations(layer_tree_host_.get());
120
121  EXPECT_CALL(*layer_tree_host_, AcquireLayerTextures()).Times(0);
122  EXPECT_CALL(*layer_tree_host_, SetNeedsUpdateLayers()).Times(1);
123  test_layer->SetNeedsDisplayRect(dirty_rect);
124  Mock::VerifyAndClearExpectations(layer_tree_host_.get());
125
126  EXPECT_CALL(*layer_tree_host_, AcquireLayerTextures()).Times(0);
127  EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(1);
128  test_layer->PushPropertiesTo(impl_layer.get());  // fake commit
129  test_layer->SetIsDrawable(false);
130  Mock::VerifyAndClearExpectations(layer_tree_host_.get());
131
132  // Verify that non-drawable layers don't signal the compositor,
133  // except for the first draw after last commit, which must acquire
134  // the texture.
135  EXPECT_CALL(*layer_tree_host_, AcquireLayerTextures()).Times(1);
136  EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(0);
137  test_layer->WillModifyTexture();
138  test_layer->SetNeedsDisplayRect(dirty_rect);
139  test_layer->PushPropertiesTo(impl_layer.get());  // fake commit
140  Mock::VerifyAndClearExpectations(layer_tree_host_.get());
141
142  // Second draw with layer in non-drawable state: no texture
143  // acquisition.
144  EXPECT_CALL(*layer_tree_host_, AcquireLayerTextures()).Times(0);
145  EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(0);
146  test_layer->WillModifyTexture();
147  test_layer->SetNeedsDisplayRect(dirty_rect);
148  Mock::VerifyAndClearExpectations(layer_tree_host_.get());
149}
150
151TEST_F(TextureLayerTest, SyncImplWhenRemovingFromTree) {
152  scoped_refptr<Layer> root_layer = Layer::Create();
153  ASSERT_TRUE(root_layer.get());
154  scoped_refptr<Layer> child_layer = Layer::Create();
155  ASSERT_TRUE(child_layer.get());
156  root_layer->AddChild(child_layer);
157  scoped_refptr<TextureLayer> test_layer = TextureLayer::Create(NULL);
158  ASSERT_TRUE(test_layer.get());
159  test_layer->SetTextureId(0);
160  child_layer->AddChild(test_layer);
161
162  EXPECT_CALL(*layer_tree_host_, AcquireLayerTextures()).Times(AnyNumber());
163  EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AnyNumber());
164  layer_tree_host_->SetRootLayer(root_layer);
165  Mock::VerifyAndClearExpectations(layer_tree_host_.get());
166
167  EXPECT_CALL(*layer_tree_host_, AcquireLayerTextures()).Times(0);
168  EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AtLeast(1));
169  test_layer->RemoveFromParent();
170  Mock::VerifyAndClearExpectations(layer_tree_host_.get());
171
172  EXPECT_CALL(*layer_tree_host_, AcquireLayerTextures()).Times(0);
173  EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AtLeast(1));
174  child_layer->AddChild(test_layer);
175  Mock::VerifyAndClearExpectations(layer_tree_host_.get());
176
177  EXPECT_CALL(*layer_tree_host_, AcquireLayerTextures()).Times(0);
178  EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AtLeast(1));
179  test_layer->SetTextureId(1);
180  Mock::VerifyAndClearExpectations(layer_tree_host_.get());
181
182  EXPECT_CALL(*layer_tree_host_, AcquireLayerTextures()).Times(AtLeast(1));
183  EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AtLeast(1));
184  test_layer->RemoveFromParent();
185  Mock::VerifyAndClearExpectations(layer_tree_host_.get());
186}
187
188TEST_F(TextureLayerTest, CheckPropertyChangeCausesCorrectBehavior) {
189  scoped_refptr<TextureLayer> test_layer = TextureLayer::Create(NULL);
190  layer_tree_host_->SetRootLayer(test_layer);
191
192  // Test properties that should call SetNeedsCommit.  All properties need to
193  // be set to new values in order for SetNeedsCommit to be called.
194  EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetFlipped(false));
195  EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetUV(
196      gfx::PointF(0.25f, 0.25f), gfx::PointF(0.75f, 0.75f)));
197  EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetVertexOpacity(
198      0.5f, 0.5f, 0.5f, 0.5f));
199  EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetPremultipliedAlpha(false));
200  EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetBlendBackgroundColor(true));
201  EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetTextureId(1));
202
203  // Calling SetTextureId can call AcquireLayerTextures.
204  EXPECT_CALL(*layer_tree_host_, AcquireLayerTextures()).Times(AnyNumber());
205}
206
207TEST_F(TextureLayerTest, VisibleContentOpaqueRegion) {
208  const gfx::Size layer_bounds(100, 100);
209  const gfx::Rect layer_rect(layer_bounds);
210  const Region layer_region(layer_rect);
211
212  scoped_refptr<TextureLayer> layer = TextureLayer::Create(NULL);
213  layer->SetBounds(layer_bounds);
214  layer->draw_properties().visible_content_rect = layer_rect;
215  layer->SetBlendBackgroundColor(true);
216
217  // Verify initial conditions.
218  EXPECT_FALSE(layer->contents_opaque());
219  EXPECT_EQ(0u, layer->background_color());
220  EXPECT_EQ(Region().ToString(),
221            layer->VisibleContentOpaqueRegion().ToString());
222
223  // Opaque background.
224  layer->SetBackgroundColor(SK_ColorWHITE);
225  EXPECT_EQ(layer_region.ToString(),
226            layer->VisibleContentOpaqueRegion().ToString());
227
228  // Transparent background.
229  layer->SetBackgroundColor(SkColorSetARGB(100, 255, 255, 255));
230  EXPECT_EQ(Region().ToString(),
231            layer->VisibleContentOpaqueRegion().ToString());
232}
233
234class FakeTextureLayerClient : public TextureLayerClient {
235 public:
236  FakeTextureLayerClient() : context_(TestWebGraphicsContext3D::Create()) {}
237
238  virtual unsigned PrepareTexture() OVERRIDE {
239    return 0;
240  }
241
242  virtual WebKit::WebGraphicsContext3D* Context3d() OVERRIDE {
243    return context_.get();
244  }
245
246  virtual bool PrepareTextureMailbox(TextureMailbox* mailbox,
247                                     bool use_shared_memory) OVERRIDE {
248    *mailbox = TextureMailbox();
249    return true;
250  }
251
252 private:
253  scoped_ptr<TestWebGraphicsContext3D> context_;
254  DISALLOW_COPY_AND_ASSIGN(FakeTextureLayerClient);
255};
256
257TEST_F(TextureLayerTest, RateLimiter) {
258  FakeTextureLayerClient client;
259  scoped_refptr<TextureLayer> test_layer = TextureLayer::CreateForMailbox(
260      &client);
261  test_layer->SetIsDrawable(true);
262  EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AnyNumber());
263  layer_tree_host_->SetRootLayer(test_layer);
264
265  // Don't rate limit until we invalidate.
266  EXPECT_CALL(*layer_tree_host_, StartRateLimiter(_)).Times(0);
267  test_layer->SetRateLimitContext(true);
268  Mock::VerifyAndClearExpectations(layer_tree_host_.get());
269
270  // Do rate limit after we invalidate.
271  EXPECT_CALL(*layer_tree_host_, StartRateLimiter(client.Context3d()));
272  test_layer->SetNeedsDisplay();
273  Mock::VerifyAndClearExpectations(layer_tree_host_.get());
274
275  // Stop rate limiter when we don't want it any more.
276  EXPECT_CALL(*layer_tree_host_, StopRateLimiter(client.Context3d()));
277  test_layer->SetRateLimitContext(false);
278  Mock::VerifyAndClearExpectations(layer_tree_host_.get());
279
280  // Or we clear the client.
281  test_layer->SetRateLimitContext(true);
282  EXPECT_CALL(*layer_tree_host_, StopRateLimiter(client.Context3d()));
283  EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AnyNumber());
284  test_layer->ClearClient();
285  Mock::VerifyAndClearExpectations(layer_tree_host_.get());
286
287  // Reset to a layer with a client, that started the rate limiter.
288  test_layer = TextureLayer::CreateForMailbox(
289      &client);
290  test_layer->SetIsDrawable(true);
291  test_layer->SetRateLimitContext(true);
292  EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AnyNumber());
293  layer_tree_host_->SetRootLayer(test_layer);
294  EXPECT_CALL(*layer_tree_host_, StartRateLimiter(_)).Times(0);
295  Mock::VerifyAndClearExpectations(layer_tree_host_.get());
296  EXPECT_CALL(*layer_tree_host_, StartRateLimiter(client.Context3d()));
297  test_layer->SetNeedsDisplay();
298  Mock::VerifyAndClearExpectations(layer_tree_host_.get());
299
300  // Stop rate limiter when we're removed from the tree.
301  EXPECT_CALL(*layer_tree_host_, StopRateLimiter(client.Context3d()));
302  layer_tree_host_->SetRootLayer(NULL);
303  Mock::VerifyAndClearExpectations(layer_tree_host_.get());
304}
305
306class MockMailboxCallback {
307 public:
308  MOCK_METHOD3(Release, void(const std::string& mailbox,
309                             unsigned sync_point,
310                             bool lost_resource));
311  MOCK_METHOD3(Release2, void(base::SharedMemory* shared_memory,
312                              unsigned sync_point,
313                              bool lost_resource));
314};
315
316struct CommonMailboxObjects {
317  CommonMailboxObjects()
318      : mailbox_name1_(64, '1'),
319        mailbox_name2_(64, '2'),
320        sync_point1_(1),
321        sync_point2_(2),
322        shared_memory_(new base::SharedMemory) {
323    release_mailbox1_ = base::Bind(&MockMailboxCallback::Release,
324                                   base::Unretained(&mock_callback_),
325                                   mailbox_name1_);
326    release_mailbox2_ = base::Bind(&MockMailboxCallback::Release,
327                                   base::Unretained(&mock_callback_),
328                                   mailbox_name2_);
329    gpu::Mailbox m1;
330    m1.SetName(reinterpret_cast<const int8*>(mailbox_name1_.data()));
331    mailbox1_ = TextureMailbox(m1, release_mailbox1_, sync_point1_);
332    gpu::Mailbox m2;
333    m2.SetName(reinterpret_cast<const int8*>(mailbox_name2_.data()));
334    mailbox2_ = TextureMailbox(m2, release_mailbox2_, sync_point2_);
335
336    gfx::Size size(128, 128);
337    EXPECT_TRUE(shared_memory_->CreateAndMapAnonymous(4 * size.GetArea()));
338    release_mailbox3_ = base::Bind(&MockMailboxCallback::Release2,
339                                   base::Unretained(&mock_callback_),
340                                   shared_memory_.get());
341    mailbox3_ = TextureMailbox(shared_memory_.get(), size, release_mailbox3_);
342  }
343
344  std::string mailbox_name1_;
345  std::string mailbox_name2_;
346  MockMailboxCallback mock_callback_;
347  TextureMailbox::ReleaseCallback release_mailbox1_;
348  TextureMailbox::ReleaseCallback release_mailbox2_;
349  TextureMailbox::ReleaseCallback release_mailbox3_;
350  TextureMailbox mailbox1_;
351  TextureMailbox mailbox2_;
352  TextureMailbox mailbox3_;
353  unsigned sync_point1_;
354  unsigned sync_point2_;
355  scoped_ptr<base::SharedMemory> shared_memory_;
356};
357
358class TextureLayerWithMailboxTest : public TextureLayerTest {
359 protected:
360  virtual void TearDown() {
361    Mock::VerifyAndClearExpectations(&test_data_.mock_callback_);
362    EXPECT_CALL(test_data_.mock_callback_,
363                Release(test_data_.mailbox_name1_,
364                        test_data_.sync_point1_,
365                        false)).Times(1);
366    TextureLayerTest::TearDown();
367  }
368
369  CommonMailboxObjects test_data_;
370};
371
372TEST_F(TextureLayerWithMailboxTest, ReplaceMailboxOnMainThreadBeforeCommit) {
373  scoped_refptr<TextureLayer> test_layer = TextureLayer::CreateForMailbox(NULL);
374  ASSERT_TRUE(test_layer.get());
375
376  EXPECT_CALL(*layer_tree_host_, AcquireLayerTextures()).Times(0);
377  EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AnyNumber());
378  layer_tree_host_->SetRootLayer(test_layer);
379  Mock::VerifyAndClearExpectations(layer_tree_host_.get());
380
381  EXPECT_CALL(*layer_tree_host_, AcquireLayerTextures()).Times(0);
382  EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AtLeast(1));
383  test_layer->SetTextureMailbox(test_data_.mailbox1_);
384  Mock::VerifyAndClearExpectations(layer_tree_host_.get());
385
386  EXPECT_CALL(*layer_tree_host_, AcquireLayerTextures()).Times(0);
387  EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AtLeast(1));
388  EXPECT_CALL(test_data_.mock_callback_,
389              Release(test_data_.mailbox_name1_,
390                      test_data_.sync_point1_,
391                      false))
392      .Times(1);
393  test_layer->SetTextureMailbox(test_data_.mailbox2_);
394  Mock::VerifyAndClearExpectations(layer_tree_host_.get());
395  Mock::VerifyAndClearExpectations(&test_data_.mock_callback_);
396
397  EXPECT_CALL(*layer_tree_host_, AcquireLayerTextures()).Times(0);
398  EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AtLeast(1));
399  EXPECT_CALL(test_data_.mock_callback_,
400              Release(test_data_.mailbox_name2_,
401                      test_data_.sync_point2_,
402                      false))
403      .Times(1);
404  test_layer->SetTextureMailbox(TextureMailbox());
405  Mock::VerifyAndClearExpectations(layer_tree_host_.get());
406  Mock::VerifyAndClearExpectations(&test_data_.mock_callback_);
407
408  test_layer->SetTextureMailbox(test_data_.mailbox3_);
409  Mock::VerifyAndClearExpectations(layer_tree_host_.get());
410  Mock::VerifyAndClearExpectations(&test_data_.mock_callback_);
411
412  EXPECT_CALL(*layer_tree_host_, AcquireLayerTextures()).Times(0);
413  EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AtLeast(1));
414  EXPECT_CALL(test_data_.mock_callback_,
415              Release2(test_data_.shared_memory_.get(),
416                       0, false))
417      .Times(1);
418  test_layer->SetTextureMailbox(TextureMailbox());
419  Mock::VerifyAndClearExpectations(layer_tree_host_.get());
420  Mock::VerifyAndClearExpectations(&test_data_.mock_callback_);
421
422  // Test destructor.
423  EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AtLeast(1));
424  test_layer->SetTextureMailbox(test_data_.mailbox1_);
425}
426
427class TextureLayerImplWithMailboxThreadedCallback : public LayerTreeTest {
428 public:
429  TextureLayerImplWithMailboxThreadedCallback()
430      : callback_count_(0),
431        commit_count_(0) {}
432
433  // Make sure callback is received on main and doesn't block the impl thread.
434  void ReleaseCallback(unsigned sync_point, bool lost_resource) {
435    EXPECT_EQ(true, proxy()->IsMainThread());
436    EXPECT_FALSE(lost_resource);
437    ++callback_count_;
438  }
439
440  void SetMailbox(char mailbox_char) {
441    TextureMailbox mailbox(
442        std::string(64, mailbox_char),
443        base::Bind(
444            &TextureLayerImplWithMailboxThreadedCallback::ReleaseCallback,
445            base::Unretained(this)));
446    layer_->SetTextureMailbox(mailbox);
447  }
448
449  virtual void BeginTest() OVERRIDE {
450    gfx::Size bounds(100, 100);
451    root_ = Layer::Create();
452    root_->SetAnchorPoint(gfx::PointF());
453    root_->SetBounds(bounds);
454
455    layer_ = TextureLayer::CreateForMailbox(NULL);
456    layer_->SetIsDrawable(true);
457    layer_->SetAnchorPoint(gfx::PointF());
458    layer_->SetBounds(bounds);
459
460    root_->AddChild(layer_);
461    layer_tree_host()->SetRootLayer(root_);
462    layer_tree_host()->SetViewportSize(bounds);
463    SetMailbox('1');
464    EXPECT_EQ(0, callback_count_);
465
466    // Case #1: change mailbox before the commit. The old mailbox should be
467    // released immediately.
468    SetMailbox('2');
469    EXPECT_EQ(1, callback_count_);
470    PostSetNeedsCommitToMainThread();
471  }
472
473  virtual void DidCommit() OVERRIDE {
474    ++commit_count_;
475    switch (commit_count_) {
476      case 1:
477        // Case #2: change mailbox after the commit (and draw), where the
478        // layer draws. The old mailbox should be released during the next
479        // commit.
480        SetMailbox('3');
481        EXPECT_EQ(1, callback_count_);
482        break;
483      case 2:
484        // Old mailbox was released, task was posted, but won't execute
485        // until this DidCommit returns.
486        // TODO(piman): fix this.
487        EXPECT_EQ(1, callback_count_);
488        layer_tree_host()->SetNeedsCommit();
489        break;
490      case 3:
491        EXPECT_EQ(2, callback_count_);
492        // Case #3: change mailbox when the layer doesn't draw. The old
493        // mailbox should be released during the next commit.
494        layer_->SetBounds(gfx::Size());
495        SetMailbox('4');
496        break;
497      case 4:
498        // Old mailbox was released, task was posted, but won't execute
499        // until this DidCommit returns.
500        // TODO(piman): fix this.
501        EXPECT_EQ(2, callback_count_);
502        layer_tree_host()->SetNeedsCommit();
503        break;
504      case 5:
505        EXPECT_EQ(3, callback_count_);
506        // Case #4: release mailbox that was committed but never drawn. The
507        // old mailbox should be released during the next commit.
508        layer_->SetTextureMailbox(TextureMailbox());
509        break;
510      case 6:
511        // Old mailbox was released, task was posted, but won't execute
512        // until this DidCommit returns.
513        // TODO(piman): fix this.
514        EXPECT_EQ(3, callback_count_);
515        layer_tree_host()->SetNeedsCommit();
516        break;
517      case 7:
518        EXPECT_EQ(4, callback_count_);
519        // Restore a mailbox for the next step.
520        SetMailbox('5');
521        break;
522      case 8:
523        // Case #5: remove layer from tree. Callback should *not* be called, the
524        // mailbox is returned to the main thread.
525        EXPECT_EQ(4, callback_count_);
526        layer_->RemoveFromParent();
527        break;
528      case 9:
529        // Mailbox was released to the main thread, task was posted, but won't
530        // execute until this DidCommit returns.
531        // TODO(piman): fix this.
532        EXPECT_EQ(4, callback_count_);
533        layer_tree_host()->SetNeedsCommit();
534        break;
535      case 10:
536        EXPECT_EQ(4, callback_count_);
537        // Resetting the mailbox will call the callback now.
538        layer_->SetTextureMailbox(TextureMailbox());
539        EXPECT_EQ(5, callback_count_);
540        EndTest();
541        break;
542      default:
543        NOTREACHED();
544        break;
545    }
546  }
547
548  virtual void AfterTest() OVERRIDE {}
549
550 private:
551  int callback_count_;
552  int commit_count_;
553  scoped_refptr<Layer> root_;
554  scoped_refptr<TextureLayer> layer_;
555};
556
557SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F(
558    TextureLayerImplWithMailboxThreadedCallback);
559
560class TextureLayerImplWithMailboxTest : public TextureLayerTest {
561 protected:
562  TextureLayerImplWithMailboxTest()
563      : fake_client_(
564          FakeLayerTreeHostClient(FakeLayerTreeHostClient::DIRECT_3D)) {}
565
566  virtual void SetUp() {
567    TextureLayerTest::SetUp();
568    layer_tree_host_.reset(new MockLayerTreeHost(&fake_client_));
569    EXPECT_TRUE(host_impl_.InitializeRenderer(CreateFakeOutputSurface()));
570  }
571
572  bool WillDraw(TextureLayerImpl* layer, DrawMode mode) {
573    bool will_draw = layer->WillDraw(
574        mode, host_impl_.active_tree()->resource_provider());
575    if (will_draw)
576      layer->DidDraw(host_impl_.active_tree()->resource_provider());
577    return will_draw;
578  }
579
580  CommonMailboxObjects test_data_;
581  FakeLayerTreeHostClient fake_client_;
582};
583
584// Test conditions for results of TextureLayerImpl::WillDraw under
585// different configurations of different mailbox, texture_id, and draw_mode.
586TEST_F(TextureLayerImplWithMailboxTest, TestWillDraw) {
587  EXPECT_CALL(test_data_.mock_callback_,
588              Release(test_data_.mailbox_name1_,
589                      test_data_.sync_point1_,
590                      false))
591      .Times(AnyNumber());
592  EXPECT_CALL(test_data_.mock_callback_,
593              Release2(test_data_.shared_memory_.get(), 0, false))
594      .Times(AnyNumber());
595  // Hardware mode.
596  {
597    scoped_ptr<TextureLayerImpl> impl_layer =
598        TextureLayerImpl::Create(host_impl_.active_tree(), 1, true);
599    impl_layer->SetTextureMailbox(test_data_.mailbox1_);
600    EXPECT_TRUE(WillDraw(impl_layer.get(), DRAW_MODE_HARDWARE));
601  }
602
603  {
604    scoped_ptr<TextureLayerImpl> impl_layer =
605        TextureLayerImpl::Create(host_impl_.active_tree(), 1, true);
606    impl_layer->SetTextureMailbox(TextureMailbox());
607    EXPECT_FALSE(WillDraw(impl_layer.get(), DRAW_MODE_HARDWARE));
608  }
609
610  {
611    // Software resource.
612    scoped_ptr<TextureLayerImpl> impl_layer =
613        TextureLayerImpl::Create(host_impl_.active_tree(), 1, true);
614    impl_layer->SetTextureMailbox(test_data_.mailbox3_);
615    EXPECT_TRUE(WillDraw(impl_layer.get(), DRAW_MODE_HARDWARE));
616  }
617
618  {
619    scoped_ptr<TextureLayerImpl> impl_layer =
620        TextureLayerImpl::Create(host_impl_.active_tree(), 1, false);
621    unsigned texture =
622        host_impl_.output_surface()->context3d()->createTexture();
623    impl_layer->set_texture_id(texture);
624    EXPECT_TRUE(WillDraw(impl_layer.get(), DRAW_MODE_HARDWARE));
625  }
626
627  {
628    scoped_ptr<TextureLayerImpl> impl_layer =
629        TextureLayerImpl::Create(host_impl_.active_tree(), 1, false);
630    impl_layer->set_texture_id(0);
631    EXPECT_FALSE(WillDraw(impl_layer.get(), DRAW_MODE_HARDWARE));
632  }
633
634  // Software mode.
635  {
636    scoped_ptr<TextureLayerImpl> impl_layer =
637        TextureLayerImpl::Create(host_impl_.active_tree(), 1, true);
638    impl_layer->SetTextureMailbox(test_data_.mailbox1_);
639    EXPECT_FALSE(WillDraw(impl_layer.get(), DRAW_MODE_SOFTWARE));
640  }
641
642  {
643    scoped_ptr<TextureLayerImpl> impl_layer =
644        TextureLayerImpl::Create(host_impl_.active_tree(), 1, true);
645    impl_layer->SetTextureMailbox(TextureMailbox());
646    EXPECT_FALSE(WillDraw(impl_layer.get(), DRAW_MODE_SOFTWARE));
647  }
648
649  {
650    // Software resource.
651    scoped_ptr<TextureLayerImpl> impl_layer =
652        TextureLayerImpl::Create(host_impl_.active_tree(), 1, true);
653    impl_layer->SetTextureMailbox(test_data_.mailbox3_);
654    EXPECT_TRUE(WillDraw(impl_layer.get(), DRAW_MODE_SOFTWARE));
655  }
656
657  {
658    scoped_ptr<TextureLayerImpl> impl_layer =
659        TextureLayerImpl::Create(host_impl_.active_tree(), 1, false);
660    unsigned texture =
661        host_impl_.output_surface()->context3d()->createTexture();
662    impl_layer->set_texture_id(texture);
663    EXPECT_FALSE(WillDraw(impl_layer.get(), DRAW_MODE_SOFTWARE));
664  }
665
666  {
667    scoped_ptr<TextureLayerImpl> impl_layer =
668        TextureLayerImpl::Create(host_impl_.active_tree(), 1, false);
669    impl_layer->set_texture_id(0);
670    EXPECT_FALSE(WillDraw(impl_layer.get(), DRAW_MODE_SOFTWARE));
671  }
672
673  // Resourceless software mode.
674  {
675    scoped_ptr<TextureLayerImpl> impl_layer =
676        TextureLayerImpl::Create(host_impl_.active_tree(), 1, true);
677    impl_layer->SetTextureMailbox(test_data_.mailbox1_);
678    EXPECT_FALSE(WillDraw(impl_layer.get(), DRAW_MODE_RESOURCELESS_SOFTWARE));
679  }
680
681  {
682    scoped_ptr<TextureLayerImpl> impl_layer =
683        TextureLayerImpl::Create(host_impl_.active_tree(), 1, false);
684    unsigned texture =
685        host_impl_.output_surface()->context3d()->createTexture();
686    impl_layer->set_texture_id(texture);
687    EXPECT_FALSE(WillDraw(impl_layer.get(), DRAW_MODE_RESOURCELESS_SOFTWARE));
688  }
689}
690
691TEST_F(TextureLayerImplWithMailboxTest, TestImplLayerCallbacks) {
692  host_impl_.CreatePendingTree();
693  scoped_ptr<TextureLayerImpl> pending_layer;
694  pending_layer = TextureLayerImpl::Create(host_impl_.pending_tree(), 1, true);
695  ASSERT_TRUE(pending_layer);
696
697  scoped_ptr<LayerImpl> active_layer(
698      pending_layer->CreateLayerImpl(host_impl_.active_tree()));
699  ASSERT_TRUE(active_layer);
700
701  pending_layer->SetTextureMailbox(test_data_.mailbox1_);
702
703  // Test multiple commits without an activation.
704  EXPECT_CALL(test_data_.mock_callback_,
705              Release(test_data_.mailbox_name1_,
706                      test_data_.sync_point1_,
707                      false))
708      .Times(1);
709  pending_layer->SetTextureMailbox(test_data_.mailbox2_);
710  Mock::VerifyAndClearExpectations(&test_data_.mock_callback_);
711
712  // Test callback after activation.
713  pending_layer->PushPropertiesTo(active_layer.get());
714  active_layer->DidBecomeActive();
715
716  EXPECT_CALL(test_data_.mock_callback_, Release(_, _, _)).Times(0);
717  pending_layer->SetTextureMailbox(test_data_.mailbox1_);
718  Mock::VerifyAndClearExpectations(&test_data_.mock_callback_);
719
720  EXPECT_CALL(test_data_.mock_callback_,
721              Release(test_data_.mailbox_name2_, _, false))
722      .Times(1);
723  pending_layer->PushPropertiesTo(active_layer.get());
724  active_layer->DidBecomeActive();
725  Mock::VerifyAndClearExpectations(&test_data_.mock_callback_);
726
727  // Test resetting the mailbox.
728  EXPECT_CALL(test_data_.mock_callback_,
729              Release(test_data_.mailbox_name1_, _, false))
730      .Times(1);
731  pending_layer->SetTextureMailbox(TextureMailbox());
732  pending_layer->PushPropertiesTo(active_layer.get());
733  active_layer->DidBecomeActive();
734  Mock::VerifyAndClearExpectations(&test_data_.mock_callback_);
735
736  // Test destructor.
737  EXPECT_CALL(test_data_.mock_callback_,
738              Release(test_data_.mailbox_name1_,
739                      test_data_.sync_point1_,
740                      false))
741      .Times(1);
742  pending_layer->SetTextureMailbox(test_data_.mailbox1_);
743}
744
745TEST_F(TextureLayerImplWithMailboxTest,
746       TestDestructorCallbackOnCreatedResource) {
747  scoped_ptr<TextureLayerImpl> impl_layer;
748  impl_layer = TextureLayerImpl::Create(host_impl_.active_tree(), 1, true);
749  ASSERT_TRUE(impl_layer);
750
751  EXPECT_CALL(test_data_.mock_callback_,
752              Release(test_data_.mailbox_name1_, _, false))
753      .Times(1);
754  impl_layer->SetTextureMailbox(test_data_.mailbox1_);
755  impl_layer->DidBecomeActive();
756  EXPECT_TRUE(impl_layer->WillDraw(
757      DRAW_MODE_HARDWARE, host_impl_.active_tree()->resource_provider()));
758  impl_layer->DidDraw(host_impl_.active_tree()->resource_provider());
759  impl_layer->SetTextureMailbox(TextureMailbox());
760}
761
762TEST_F(TextureLayerImplWithMailboxTest, TestCallbackOnInUseResource) {
763  ResourceProvider* provider = host_impl_.active_tree()->resource_provider();
764  ResourceProvider::ResourceId id =
765      provider->CreateResourceFromTextureMailbox(test_data_.mailbox1_);
766  provider->AllocateForTesting(id);
767
768  // Transfer some resources to the parent.
769  ResourceProvider::ResourceIdArray resource_ids_to_transfer;
770  resource_ids_to_transfer.push_back(id);
771  TransferableResourceArray list;
772  provider->PrepareSendToParent(resource_ids_to_transfer, &list);
773  EXPECT_TRUE(provider->InUseByConsumer(id));
774  EXPECT_CALL(test_data_.mock_callback_, Release(_, _, _)).Times(0);
775  provider->DeleteResource(id);
776  Mock::VerifyAndClearExpectations(&test_data_.mock_callback_);
777  EXPECT_CALL(test_data_.mock_callback_,
778              Release(test_data_.mailbox_name1_, _, false))
779      .Times(1);
780  provider->ReceiveFromParent(list);
781}
782
783// Check that ClearClient correctly clears the state so that the impl side
784// doesn't try to use a texture that could have been destroyed.
785class TextureLayerClientTest
786    : public LayerTreeTest,
787      public TextureLayerClient {
788 public:
789  TextureLayerClientTest()
790      : context_(NULL),
791        texture_(0),
792        commit_count_(0),
793        expected_used_textures_on_draw_(0),
794        expected_used_textures_on_commit_(0) {}
795
796  virtual scoped_ptr<OutputSurface> CreateOutputSurface(bool fallback)
797      OVERRIDE {
798    scoped_ptr<TestWebGraphicsContext3D> context(
799        TestWebGraphicsContext3D::Create());
800    context_ = context.get();
801    texture_ = context->createTexture();
802    return FakeOutputSurface::Create3d(
803        context.PassAs<WebKit::WebGraphicsContext3D>()).PassAs<OutputSurface>();
804  }
805
806  virtual unsigned PrepareTexture() OVERRIDE {
807    return texture_;
808  }
809
810  virtual WebKit::WebGraphicsContext3D* Context3d() OVERRIDE {
811    return context_;
812  }
813
814  virtual bool PrepareTextureMailbox(
815      cc::TextureMailbox* mailbox, bool use_shared_memory) OVERRIDE {
816    return false;
817  }
818
819  virtual void SetupTree() OVERRIDE {
820    scoped_refptr<Layer> root = Layer::Create();
821    root->SetBounds(gfx::Size(10, 10));
822    root->SetAnchorPoint(gfx::PointF());
823    root->SetIsDrawable(true);
824
825    texture_layer_ = TextureLayer::Create(this);
826    texture_layer_->SetBounds(gfx::Size(10, 10));
827    texture_layer_->SetAnchorPoint(gfx::PointF());
828    texture_layer_->SetIsDrawable(true);
829    root->AddChild(texture_layer_);
830
831    layer_tree_host()->SetRootLayer(root);
832    LayerTreeTest::SetupTree();
833    {
834      base::AutoLock lock(lock_);
835      expected_used_textures_on_commit_ = 1;
836    }
837  }
838
839  virtual void BeginTest() OVERRIDE {
840    PostSetNeedsCommitToMainThread();
841  }
842
843  virtual void DidCommitAndDrawFrame() OVERRIDE {
844    ++commit_count_;
845    switch (commit_count_) {
846      case 1:
847        texture_layer_->ClearClient();
848        texture_layer_->SetNeedsDisplay();
849        {
850          base::AutoLock lock(lock_);
851          expected_used_textures_on_commit_ = 0;
852        }
853        texture_ = 0;
854        break;
855      case 2:
856        EndTest();
857        break;
858      default:
859        NOTREACHED();
860        break;
861    }
862  }
863
864  virtual void BeginCommitOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
865    base::AutoLock lock(lock_);
866    expected_used_textures_on_draw_ = expected_used_textures_on_commit_;
867  }
868
869  virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
870                                     LayerTreeHostImpl::FrameData* frame_data,
871                                     bool result) OVERRIDE {
872    context_->ResetUsedTextures();
873    return true;
874  }
875
876  virtual void SwapBuffersOnThread(LayerTreeHostImpl* host_impl,
877                                   bool result) OVERRIDE {
878    ASSERT_TRUE(result);
879    EXPECT_EQ(expected_used_textures_on_draw_, context_->NumUsedTextures());
880  }
881
882  virtual void AfterTest() OVERRIDE {}
883
884 private:
885  scoped_refptr<TextureLayer> texture_layer_;
886  TestWebGraphicsContext3D* context_;
887  unsigned texture_;
888  int commit_count_;
889
890  // Used only on thread.
891  unsigned expected_used_textures_on_draw_;
892
893  // Used on either thread, protected by lock_.
894  base::Lock lock_;
895  unsigned expected_used_textures_on_commit_;
896};
897
898// The TextureLayerClient does not use mailboxes, so can't use a delegating
899// renderer.
900SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F(TextureLayerClientTest);
901
902// Test recovering from a lost context.
903class TextureLayerLostContextTest
904    : public LayerTreeTest,
905      public TextureLayerClient {
906 public:
907  TextureLayerLostContextTest()
908      : texture_(0),
909        draw_count_(0) {}
910
911  virtual scoped_ptr<OutputSurface> CreateOutputSurface(bool fallback)
912      OVERRIDE {
913    texture_context_ = TestWebGraphicsContext3D::Create();
914    texture_ = texture_context_->createTexture();
915    return CreateFakeOutputSurface();
916  }
917
918  virtual unsigned PrepareTexture() OVERRIDE {
919    if (draw_count_ == 0) {
920      texture_context_->loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB,
921          GL_INNOCENT_CONTEXT_RESET_ARB);
922    }
923    return texture_;
924  }
925
926  virtual WebKit::WebGraphicsContext3D* Context3d() OVERRIDE {
927    return texture_context_.get();
928  }
929
930  virtual bool PrepareTextureMailbox(
931      cc::TextureMailbox* mailbox, bool use_shared_memory) OVERRIDE {
932    return false;
933  }
934
935  virtual void SetupTree() OVERRIDE {
936    scoped_refptr<Layer> root = Layer::Create();
937    root->SetBounds(gfx::Size(10, 10));
938    root->SetIsDrawable(true);
939
940    texture_layer_ = TextureLayer::Create(this);
941    texture_layer_->SetBounds(gfx::Size(10, 10));
942    texture_layer_->SetIsDrawable(true);
943    root->AddChild(texture_layer_);
944
945    layer_tree_host()->SetRootLayer(root);
946    LayerTreeTest::SetupTree();
947  }
948
949  virtual void BeginTest() OVERRIDE {
950    PostSetNeedsCommitToMainThread();
951  }
952
953  virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
954                                     LayerTreeHostImpl::FrameData* frame_data,
955                                     bool result) OVERRIDE {
956    LayerImpl* root = host_impl->RootLayer();
957    TextureLayerImpl* texture_layer =
958        static_cast<TextureLayerImpl*>(root->children()[0]);
959    if (++draw_count_ == 1)
960      EXPECT_EQ(0u, texture_layer->texture_id());
961    else
962      EXPECT_EQ(texture_, texture_layer->texture_id());
963    return true;
964  }
965
966  virtual void DidCommitAndDrawFrame() OVERRIDE {
967    EndTest();
968  }
969
970  virtual void AfterTest() OVERRIDE {}
971
972 private:
973  scoped_refptr<TextureLayer> texture_layer_;
974  scoped_ptr<TestWebGraphicsContext3D> texture_context_;
975  unsigned texture_;
976  int draw_count_;
977};
978
979SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F(TextureLayerLostContextTest);
980
981class TextureLayerWithMailboxMainThreadDeleted : public LayerTreeTest {
982 public:
983  void ReleaseCallback(unsigned sync_point, bool lost_resource) {
984    EXPECT_EQ(true, proxy()->IsMainThread());
985    EXPECT_FALSE(lost_resource);
986    ++callback_count_;
987    EndTest();
988  }
989
990  void SetMailbox(char mailbox_char) {
991    TextureMailbox mailbox(
992        std::string(64, mailbox_char),
993        base::Bind(
994            &TextureLayerWithMailboxMainThreadDeleted::ReleaseCallback,
995            base::Unretained(this)));
996    layer_->SetTextureMailbox(mailbox);
997  }
998
999  virtual void SetupTree() OVERRIDE {
1000    gfx::Size bounds(100, 100);
1001    root_ = Layer::Create();
1002    root_->SetAnchorPoint(gfx::PointF());
1003    root_->SetBounds(bounds);
1004
1005    layer_ = TextureLayer::CreateForMailbox(NULL);
1006    layer_->SetIsDrawable(true);
1007    layer_->SetAnchorPoint(gfx::PointF());
1008    layer_->SetBounds(bounds);
1009
1010    root_->AddChild(layer_);
1011    layer_tree_host()->SetRootLayer(root_);
1012    layer_tree_host()->SetViewportSize(bounds);
1013  }
1014
1015  virtual void BeginTest() OVERRIDE {
1016    callback_count_ = 0;
1017
1018    // Set the mailbox on the main thread.
1019    SetMailbox('1');
1020    EXPECT_EQ(0, callback_count_);
1021
1022    PostSetNeedsCommitToMainThread();
1023  }
1024
1025  virtual void DidCommitAndDrawFrame() OVERRIDE {
1026    switch (layer_tree_host()->source_frame_number()) {
1027      case 1:
1028        // Delete the TextureLayer on the main thread while the mailbox is in
1029        // the impl tree.
1030        layer_->RemoveFromParent();
1031        layer_ = NULL;
1032        break;
1033    }
1034  }
1035
1036  virtual void AfterTest() OVERRIDE {
1037    EXPECT_EQ(1, callback_count_);
1038  }
1039
1040 private:
1041  int callback_count_;
1042  scoped_refptr<Layer> root_;
1043  scoped_refptr<TextureLayer> layer_;
1044};
1045
1046SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F(
1047    TextureLayerWithMailboxMainThreadDeleted);
1048
1049class TextureLayerWithMailboxImplThreadDeleted : public LayerTreeTest {
1050 public:
1051  void ReleaseCallback(unsigned sync_point, bool lost_resource) {
1052    EXPECT_EQ(true, proxy()->IsMainThread());
1053    EXPECT_FALSE(lost_resource);
1054    ++callback_count_;
1055    EndTest();
1056  }
1057
1058  void SetMailbox(char mailbox_char) {
1059    TextureMailbox mailbox(
1060        std::string(64, mailbox_char),
1061        base::Bind(
1062            &TextureLayerWithMailboxImplThreadDeleted::ReleaseCallback,
1063            base::Unretained(this)));
1064    layer_->SetTextureMailbox(mailbox);
1065  }
1066
1067  virtual void SetupTree() OVERRIDE {
1068    gfx::Size bounds(100, 100);
1069    root_ = Layer::Create();
1070    root_->SetAnchorPoint(gfx::PointF());
1071    root_->SetBounds(bounds);
1072
1073    layer_ = TextureLayer::CreateForMailbox(NULL);
1074    layer_->SetIsDrawable(true);
1075    layer_->SetAnchorPoint(gfx::PointF());
1076    layer_->SetBounds(bounds);
1077
1078    root_->AddChild(layer_);
1079    layer_tree_host()->SetRootLayer(root_);
1080    layer_tree_host()->SetViewportSize(bounds);
1081  }
1082
1083  virtual void BeginTest() OVERRIDE {
1084    callback_count_ = 0;
1085
1086    // Set the mailbox on the main thread.
1087    SetMailbox('1');
1088    EXPECT_EQ(0, callback_count_);
1089
1090    PostSetNeedsCommitToMainThread();
1091  }
1092
1093  virtual void DidCommitAndDrawFrame() OVERRIDE {
1094    switch (layer_tree_host()->source_frame_number()) {
1095      case 1:
1096        // Remove the TextureLayer on the main thread while the mailbox is in
1097        // the impl tree, but don't delete the TextureLayer until after the impl
1098        // tree side is deleted.
1099        layer_->RemoveFromParent();
1100        break;
1101      case 2:
1102        layer_ = NULL;
1103        break;
1104    }
1105  }
1106
1107  virtual void AfterTest() OVERRIDE {
1108    EXPECT_EQ(1, callback_count_);
1109  }
1110
1111 private:
1112  int callback_count_;
1113  scoped_refptr<Layer> root_;
1114  scoped_refptr<TextureLayer> layer_;
1115};
1116
1117SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F(
1118    TextureLayerWithMailboxImplThreadDeleted);
1119
1120}  // namespace
1121}  // namespace cc
1122