Home | History | Annotate | Download | only in layers
      1 // Copyright 2013 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 "base/bind.h"
      6 #include "base/run_loop.h"
      7 #include "base/synchronization/waitable_event.h"
      8 #include "base/threading/thread.h"
      9 #include "cc/layers/delegated_frame_resource_collection.h"
     10 #include "cc/resources/returned_resource.h"
     11 #include "cc/resources/transferable_resource.h"
     12 #include "testing/gtest/include/gtest/gtest.h"
     13 
     14 namespace cc {
     15 namespace {
     16 
     17 class DelegatedFrameResourceCollectionTest
     18     : public testing::Test,
     19       public DelegatedFrameResourceCollectionClient {
     20  protected:
     21   DelegatedFrameResourceCollectionTest() : resources_available_(false) {}
     22 
     23   virtual void SetUp() OVERRIDE { CreateResourceCollection(); }
     24 
     25   virtual void TearDown() OVERRIDE { DestroyResourceCollection(); }
     26 
     27   void CreateResourceCollection() {
     28     DCHECK(!resource_collection_);
     29     resource_collection_ = new DelegatedFrameResourceCollection;
     30     resource_collection_->SetClient(this);
     31   }
     32 
     33   void DestroyResourceCollection() {
     34     if (resource_collection_) {
     35       resource_collection_->SetClient(NULL);
     36       resource_collection_ = NULL;
     37     }
     38   }
     39 
     40   TransferableResourceArray CreateResourceArray() {
     41     TransferableResourceArray resources;
     42     TransferableResource resource;
     43     resource.id = 444;
     44     resources.push_back(resource);
     45     return resources;
     46   }
     47 
     48   virtual void UnusedResourcesAreAvailable() OVERRIDE {
     49     resources_available_ = true;
     50     resource_collection_->TakeUnusedResourcesForChildCompositor(
     51         &returned_resources_);
     52     if (!resources_available_closure_.is_null())
     53       resources_available_closure_.Run();
     54   }
     55 
     56   bool ReturnAndResetResourcesAvailable() {
     57     bool r = resources_available_;
     58     resources_available_ = false;
     59     return r;
     60   }
     61 
     62   scoped_refptr<DelegatedFrameResourceCollection> resource_collection_;
     63   bool resources_available_;
     64   ReturnedResourceArray returned_resources_;
     65   base::Closure resources_available_closure_;
     66 };
     67 
     68 // This checks that taking the return callback doesn't take extra refcounts,
     69 // since it's sent to other threads.
     70 TEST_F(DelegatedFrameResourceCollectionTest, NoRef) {
     71   // Start with one ref.
     72   EXPECT_TRUE(resource_collection_->HasOneRef());
     73 
     74   ReturnCallback return_callback =
     75       resource_collection_->GetReturnResourcesCallbackForImplThread();
     76 
     77   // Callback shouldn't take a ref since it's sent to other threads.
     78   EXPECT_TRUE(resource_collection_->HasOneRef());
     79 }
     80 
     81 void ReturnResourcesOnThread(ReturnCallback callback,
     82                              const ReturnedResourceArray& resources,
     83                              base::WaitableEvent* event) {
     84   callback.Run(resources);
     85   if (event)
     86     event->Wait();
     87 }
     88 
     89 // Tests that the ReturnCallback can run safely on threads even after the
     90 // last references to the collection were dropped.
     91 // Flaky: crbug.com/313441
     92 TEST_F(DelegatedFrameResourceCollectionTest, Thread) {
     93   base::Thread thread("test thread");
     94   thread.Start();
     95 
     96   TransferableResourceArray resources = CreateResourceArray();
     97   resource_collection_->ReceivedResources(resources);
     98   resource_collection_->RefResources(resources);
     99 
    100   ReturnedResourceArray returned_resources;
    101   TransferableResource::ReturnResources(resources, &returned_resources);
    102 
    103   base::WaitableEvent event(false, false);
    104 
    105   {
    106     base::RunLoop run_loop;
    107     resources_available_closure_ = run_loop.QuitClosure();
    108 
    109     thread.message_loop()->PostTask(
    110         FROM_HERE,
    111         base::Bind(
    112             &ReturnResourcesOnThread,
    113             resource_collection_->GetReturnResourcesCallbackForImplThread(),
    114             returned_resources,
    115             &event));
    116 
    117     run_loop.Run();
    118   }
    119   EXPECT_TRUE(ReturnAndResetResourcesAvailable());
    120   EXPECT_EQ(1u, returned_resources_.size());
    121   EXPECT_EQ(444u, returned_resources_[0].id);
    122   EXPECT_EQ(1, returned_resources_[0].count);
    123   returned_resources_.clear();
    124 
    125   // The event prevents the return resources callback from being deleted.
    126   // Destroy the last reference from this thread to the collection before
    127   // signaling the event, to ensure any reference taken by the callback, if any,
    128   // would be the last one.
    129   DestroyResourceCollection();
    130   event.Signal();
    131 
    132   CreateResourceCollection();
    133   resource_collection_->ReceivedResources(resources);
    134   resource_collection_->RefResources(resources);
    135 
    136   // Destroy the collection before we have a chance to run the return callback.
    137   ReturnCallback return_callback =
    138       resource_collection_->GetReturnResourcesCallbackForImplThread();
    139   resource_collection_->LoseAllResources();
    140   DestroyResourceCollection();
    141 
    142   EXPECT_TRUE(ReturnAndResetResourcesAvailable());
    143   EXPECT_EQ(1u, returned_resources_.size());
    144   EXPECT_EQ(444u, returned_resources_[0].id);
    145   EXPECT_EQ(1, returned_resources_[0].count);
    146   EXPECT_TRUE(returned_resources_[0].lost);
    147   returned_resources_.clear();
    148 
    149   base::WaitableEvent* null_event = NULL;
    150   thread.message_loop()->PostTask(FROM_HERE,
    151                                   base::Bind(&ReturnResourcesOnThread,
    152                                              return_callback,
    153                                              returned_resources,
    154                                              null_event));
    155 
    156   thread.Stop();
    157 }
    158 
    159 }  // namespace
    160 }  // namespace cc
    161