Home | History | Annotate | Download | only in resources
      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/resources/resource_update_controller.h"
      6 
      7 #include "base/test/test_simple_task_runner.h"
      8 #include "cc/resources/prioritized_resource_manager.h"
      9 #include "cc/test/fake_output_surface.h"
     10 #include "cc/test/fake_output_surface_client.h"
     11 #include "cc/test/fake_proxy.h"
     12 #include "cc/test/scheduler_test_common.h"
     13 #include "cc/test/test_shared_bitmap_manager.h"
     14 #include "cc/test/test_web_graphics_context_3d.h"
     15 #include "cc/test/tiled_layer_test_common.h"
     16 #include "cc/trees/single_thread_proxy.h"  // For DebugScopedSetImplThread
     17 #include "testing/gtest/include/gtest/gtest.h"
     18 #include "third_party/khronos/GLES2/gl2ext.h"
     19 
     20 using testing::Test;
     21 
     22 namespace cc {
     23 namespace {
     24 
     25 const int kFlushPeriodFull = 4;
     26 const int kFlushPeriodPartial = kFlushPeriodFull;
     27 
     28 class ResourceUpdateControllerTest;
     29 
     30 class WebGraphicsContext3DForUploadTest : public TestWebGraphicsContext3D {
     31  public:
     32   explicit WebGraphicsContext3DForUploadTest(ResourceUpdateControllerTest* test)
     33       : test_(test) {}
     34 
     35   virtual void flush() OVERRIDE;
     36   virtual void shallowFlushCHROMIUM() OVERRIDE;
     37   virtual void texSubImage2D(GLenum target,
     38                              GLint level,
     39                              GLint xoffset,
     40                              GLint yoffset,
     41                              GLsizei width,
     42                              GLsizei height,
     43                              GLenum format,
     44                              GLenum type,
     45                              const void* pixels) OVERRIDE;
     46 
     47   virtual void getQueryObjectuivEXT(GLuint id, GLenum pname, GLuint* value)
     48       OVERRIDE;
     49 
     50  private:
     51   ResourceUpdateControllerTest* test_;
     52 };
     53 
     54 class ResourceUpdateControllerTest : public Test {
     55  public:
     56   ResourceUpdateControllerTest()
     57       : proxy_(),
     58         queue_(make_scoped_ptr(new ResourceUpdateQueue)),
     59         resource_manager_(PrioritizedResourceManager::Create(&proxy_)),
     60         query_results_available_(0),
     61         full_upload_count_expected_(0),
     62         partial_count_expected_(0),
     63         total_upload_count_expected_(0),
     64         max_upload_count_per_update_(0),
     65         num_consecutive_flushes_(0),
     66         num_dangling_uploads_(0),
     67         num_total_uploads_(0),
     68         num_total_flushes_(0) {}
     69 
     70   virtual ~ResourceUpdateControllerTest() {
     71     DebugScopedSetImplThreadAndMainThreadBlocked
     72     impl_thread_and_main_thread_blocked(&proxy_);
     73     resource_manager_->ClearAllMemory(resource_provider_.get());
     74   }
     75 
     76  public:
     77   void OnFlush() {
     78     // Check for back-to-back flushes.
     79     EXPECT_EQ(0, num_consecutive_flushes_) << "Back-to-back flushes detected.";
     80 
     81     num_dangling_uploads_ = 0;
     82     num_consecutive_flushes_++;
     83     num_total_flushes_++;
     84   }
     85 
     86   void OnUpload() {
     87     // Check for too many consecutive uploads
     88     if (num_total_uploads_ < full_upload_count_expected_) {
     89       EXPECT_LT(num_dangling_uploads_, kFlushPeriodFull)
     90           << "Too many consecutive full uploads detected.";
     91     } else {
     92       EXPECT_LT(num_dangling_uploads_, kFlushPeriodPartial)
     93           << "Too many consecutive partial uploads detected.";
     94     }
     95 
     96     num_consecutive_flushes_ = 0;
     97     num_dangling_uploads_++;
     98     num_total_uploads_++;
     99   }
    100 
    101   bool IsQueryResultAvailable() {
    102     if (!query_results_available_)
    103       return false;
    104 
    105     query_results_available_--;
    106     return true;
    107   }
    108 
    109  protected:
    110   virtual void SetUp() {
    111     bitmap_.allocN32Pixels(300, 150);
    112 
    113     for (int i = 0; i < 4; i++) {
    114       textures_[i] = PrioritizedResource::Create(resource_manager_.get(),
    115                                                  gfx::Size(300, 150),
    116                                                  RGBA_8888);
    117       textures_[i]->
    118           set_request_priority(PriorityCalculator::VisiblePriority(true));
    119     }
    120     resource_manager_->PrioritizeTextures();
    121 
    122     output_surface_ = FakeOutputSurface::Create3d(
    123         scoped_ptr<TestWebGraphicsContext3D>(
    124             new WebGraphicsContext3DForUploadTest(this)));
    125     CHECK(output_surface_->BindToClient(&output_surface_client_));
    126 
    127     shared_bitmap_manager_.reset(new TestSharedBitmapManager());
    128     resource_provider_ = ResourceProvider::Create(output_surface_.get(),
    129                                                   shared_bitmap_manager_.get(),
    130                                                   NULL,
    131                                                   0,
    132                                                   false,
    133                                                   1,
    134                                                   false);
    135   }
    136 
    137   void AppendFullUploadsOfIndexedTextureToUpdateQueue(int count,
    138                                                       int texture_index) {
    139     full_upload_count_expected_ += count;
    140     total_upload_count_expected_ += count;
    141 
    142     const gfx::Rect rect(0, 0, 300, 150);
    143     const ResourceUpdate upload = ResourceUpdate::Create(
    144         textures_[texture_index].get(), &bitmap_, rect, rect, gfx::Vector2d());
    145     for (int i = 0; i < count; i++)
    146       queue_->AppendFullUpload(upload);
    147   }
    148 
    149   void AppendFullUploadsToUpdateQueue(int count) {
    150     AppendFullUploadsOfIndexedTextureToUpdateQueue(count, 0);
    151   }
    152 
    153   void AppendPartialUploadsOfIndexedTextureToUpdateQueue(int count,
    154                                                          int texture_index) {
    155     partial_count_expected_ += count;
    156     total_upload_count_expected_ += count;
    157 
    158     const gfx::Rect rect(0, 0, 100, 100);
    159     const ResourceUpdate upload = ResourceUpdate::Create(
    160         textures_[texture_index].get(), &bitmap_, rect, rect, gfx::Vector2d());
    161     for (int i = 0; i < count; i++)
    162       queue_->AppendPartialUpload(upload);
    163   }
    164 
    165   void AppendPartialUploadsToUpdateQueue(int count) {
    166     AppendPartialUploadsOfIndexedTextureToUpdateQueue(count, 0);
    167   }
    168 
    169   void SetMaxUploadCountPerUpdate(int count) {
    170     max_upload_count_per_update_ = count;
    171   }
    172 
    173   void UpdateTextures() {
    174     DebugScopedSetImplThreadAndMainThreadBlocked
    175     impl_thread_and_main_thread_blocked(&proxy_);
    176     scoped_ptr<ResourceUpdateController> update_controller =
    177         ResourceUpdateController::Create(NULL,
    178                                          proxy_.ImplThreadTaskRunner(),
    179                                          queue_.Pass(),
    180                                          resource_provider_.get());
    181     update_controller->Finalize();
    182   }
    183 
    184   void MakeQueryResultAvailable() { query_results_available_++; }
    185 
    186  protected:
    187   // Classes required to interact and test the ResourceUpdateController
    188   FakeProxy proxy_;
    189   FakeOutputSurfaceClient output_surface_client_;
    190   scoped_ptr<OutputSurface> output_surface_;
    191   scoped_ptr<SharedBitmapManager> shared_bitmap_manager_;
    192   scoped_ptr<ResourceProvider> resource_provider_;
    193   scoped_ptr<ResourceUpdateQueue> queue_;
    194   scoped_ptr<PrioritizedResource> textures_[4];
    195   scoped_ptr<PrioritizedResourceManager> resource_manager_;
    196   SkBitmap bitmap_;
    197   int query_results_available_;
    198 
    199   // Properties / expectations of this test
    200   int full_upload_count_expected_;
    201   int partial_count_expected_;
    202   int total_upload_count_expected_;
    203   int max_upload_count_per_update_;
    204 
    205   // Dynamic properties of this test
    206   int num_consecutive_flushes_;
    207   int num_dangling_uploads_;
    208   int num_total_uploads_;
    209   int num_total_flushes_;
    210 };
    211 
    212 void WebGraphicsContext3DForUploadTest::flush() { test_->OnFlush(); }
    213 
    214 void WebGraphicsContext3DForUploadTest::shallowFlushCHROMIUM() {
    215   test_->OnFlush();
    216 }
    217 
    218 void WebGraphicsContext3DForUploadTest::texSubImage2D(GLenum target,
    219                                                       GLint level,
    220                                                       GLint xoffset,
    221                                                       GLint yoffset,
    222                                                       GLsizei width,
    223                                                       GLsizei height,
    224                                                       GLenum format,
    225                                                       GLenum type,
    226                                                       const void* pixels) {
    227   test_->OnUpload();
    228 }
    229 
    230 void WebGraphicsContext3DForUploadTest::getQueryObjectuivEXT(GLuint id,
    231                                                              GLenum pname,
    232                                                              GLuint* params) {
    233   if (pname == GL_QUERY_RESULT_AVAILABLE_EXT)
    234     *params = test_->IsQueryResultAvailable();
    235 }
    236 
    237 // ZERO UPLOADS TESTS
    238 TEST_F(ResourceUpdateControllerTest, ZeroUploads) {
    239   AppendFullUploadsToUpdateQueue(0);
    240   AppendPartialUploadsToUpdateQueue(0);
    241   UpdateTextures();
    242 
    243   EXPECT_EQ(0, num_total_flushes_);
    244   EXPECT_EQ(0, num_total_uploads_);
    245 }
    246 
    247 // ONE UPLOAD TESTS
    248 TEST_F(ResourceUpdateControllerTest, OneFullUpload) {
    249   AppendFullUploadsToUpdateQueue(1);
    250   AppendPartialUploadsToUpdateQueue(0);
    251   UpdateTextures();
    252 
    253   EXPECT_EQ(1, num_total_flushes_);
    254   EXPECT_EQ(1, num_total_uploads_);
    255   EXPECT_EQ(0, num_dangling_uploads_)
    256       << "Last upload wasn't followed by a flush.";
    257 }
    258 
    259 TEST_F(ResourceUpdateControllerTest, OnePartialUpload) {
    260   AppendFullUploadsToUpdateQueue(0);
    261   AppendPartialUploadsToUpdateQueue(1);
    262   UpdateTextures();
    263 
    264   EXPECT_EQ(1, num_total_flushes_);
    265   EXPECT_EQ(1, num_total_uploads_);
    266   EXPECT_EQ(0, num_dangling_uploads_)
    267       << "Last upload wasn't followed by a flush.";
    268 }
    269 
    270 TEST_F(ResourceUpdateControllerTest, OneFullOnePartialUpload) {
    271   AppendFullUploadsToUpdateQueue(1);
    272   AppendPartialUploadsToUpdateQueue(1);
    273   UpdateTextures();
    274 
    275   EXPECT_EQ(1, num_total_flushes_);
    276   EXPECT_EQ(2, num_total_uploads_);
    277   EXPECT_EQ(0, num_dangling_uploads_)
    278       << "Last upload wasn't followed by a flush.";
    279 }
    280 
    281 // This class of tests upload a number of textures that is a multiple
    282 // of the flush period.
    283 const int full_upload_flush_multipler = 7;
    284 const int full_count = full_upload_flush_multipler * kFlushPeriodFull;
    285 
    286 const int partial_upload_flush_multipler = 11;
    287 const int partial_count =
    288     partial_upload_flush_multipler * kFlushPeriodPartial;
    289 
    290 TEST_F(ResourceUpdateControllerTest, ManyFullUploads) {
    291   AppendFullUploadsToUpdateQueue(full_count);
    292   AppendPartialUploadsToUpdateQueue(0);
    293   UpdateTextures();
    294 
    295   EXPECT_EQ(full_upload_flush_multipler, num_total_flushes_);
    296   EXPECT_EQ(full_count, num_total_uploads_);
    297   EXPECT_EQ(0, num_dangling_uploads_)
    298       << "Last upload wasn't followed by a flush.";
    299 }
    300 
    301 TEST_F(ResourceUpdateControllerTest, ManyPartialUploads) {
    302   AppendFullUploadsToUpdateQueue(0);
    303   AppendPartialUploadsToUpdateQueue(partial_count);
    304   UpdateTextures();
    305 
    306   EXPECT_EQ(partial_upload_flush_multipler, num_total_flushes_);
    307   EXPECT_EQ(partial_count, num_total_uploads_);
    308   EXPECT_EQ(0, num_dangling_uploads_)
    309       << "Last upload wasn't followed by a flush.";
    310 }
    311 
    312 TEST_F(ResourceUpdateControllerTest, ManyFullManyPartialUploads) {
    313   AppendFullUploadsToUpdateQueue(full_count);
    314   AppendPartialUploadsToUpdateQueue(partial_count);
    315   UpdateTextures();
    316 
    317   EXPECT_EQ(full_upload_flush_multipler + partial_upload_flush_multipler,
    318             num_total_flushes_);
    319   EXPECT_EQ(full_count + partial_count, num_total_uploads_);
    320   EXPECT_EQ(0, num_dangling_uploads_)
    321       << "Last upload wasn't followed by a flush.";
    322 }
    323 
    324 class FakeResourceUpdateControllerClient
    325     : public ResourceUpdateControllerClient {
    326  public:
    327   FakeResourceUpdateControllerClient() { Reset(); }
    328   void Reset() { ready_to_finalize_called_ = false; }
    329   bool ReadyToFinalizeCalled() const { return ready_to_finalize_called_; }
    330 
    331   virtual void ReadyToFinalizeTextureUpdates() OVERRIDE {
    332     ready_to_finalize_called_ = true;
    333   }
    334 
    335  protected:
    336   bool ready_to_finalize_called_;
    337 };
    338 
    339 class FakeResourceUpdateController : public ResourceUpdateController {
    340  public:
    341   static scoped_ptr<FakeResourceUpdateController> Create(
    342       ResourceUpdateControllerClient* client,
    343       base::TestSimpleTaskRunner* task_runner,
    344       scoped_ptr<ResourceUpdateQueue> queue,
    345       ResourceProvider* resource_provider) {
    346     return make_scoped_ptr(new FakeResourceUpdateController(
    347         client, task_runner, queue.Pass(), resource_provider));
    348   }
    349 
    350   void SetNow(base::TimeTicks time) { now_ = time; }
    351   base::TimeTicks Now() const { return now_; }
    352   void SetUpdateTextureTime(base::TimeDelta time) {
    353     update_textures_time_ = time;
    354   }
    355   virtual base::TimeTicks UpdateMoreTexturesCompletionTime() OVERRIDE {
    356     size_t total_updates =
    357         resource_provider_->NumBlockingUploads() + update_more_textures_size_;
    358     return now_ + total_updates * update_textures_time_;
    359   }
    360   void SetUpdateMoreTexturesSize(size_t size) {
    361     update_more_textures_size_ = size;
    362   }
    363   virtual size_t UpdateMoreTexturesSize() const OVERRIDE {
    364     return update_more_textures_size_;
    365   }
    366 
    367  protected:
    368   FakeResourceUpdateController(ResourceUpdateControllerClient* client,
    369                                base::TestSimpleTaskRunner* task_runner,
    370                                scoped_ptr<ResourceUpdateQueue> queue,
    371                                ResourceProvider* resource_provider)
    372       : ResourceUpdateController(
    373           client, task_runner, queue.Pass(), resource_provider),
    374         resource_provider_(resource_provider),
    375         update_more_textures_size_(0) {}
    376 
    377   ResourceProvider* resource_provider_;
    378   base::TimeTicks now_;
    379   base::TimeDelta update_textures_time_;
    380   size_t update_more_textures_size_;
    381 };
    382 
    383 static void RunPendingTask(base::TestSimpleTaskRunner* task_runner,
    384                            FakeResourceUpdateController* controller) {
    385   EXPECT_TRUE(task_runner->HasPendingTask());
    386   controller->SetNow(controller->Now() + task_runner->NextPendingTaskDelay());
    387   task_runner->RunPendingTasks();
    388 }
    389 
    390 TEST_F(ResourceUpdateControllerTest, UpdateMoreTextures) {
    391   FakeResourceUpdateControllerClient client;
    392   scoped_refptr<base::TestSimpleTaskRunner> task_runner =
    393       new base::TestSimpleTaskRunner;
    394 
    395   SetMaxUploadCountPerUpdate(1);
    396   AppendFullUploadsToUpdateQueue(3);
    397   AppendPartialUploadsToUpdateQueue(0);
    398 
    399   DebugScopedSetImplThreadAndMainThreadBlocked
    400   impl_thread_and_main_thread_blocked(&proxy_);
    401   scoped_ptr<FakeResourceUpdateController> controller(
    402       FakeResourceUpdateController::Create(&client,
    403                                            task_runner.get(),
    404                                            queue_.Pass(),
    405                                            resource_provider_.get()));
    406 
    407   controller->SetNow(controller->Now() + base::TimeDelta::FromMilliseconds(1));
    408   controller->SetUpdateTextureTime(base::TimeDelta::FromMilliseconds(100));
    409   controller->SetUpdateMoreTexturesSize(1);
    410   // Not enough time for any updates.
    411   controller->PerformMoreUpdates(controller->Now() +
    412                                  base::TimeDelta::FromMilliseconds(90));
    413   EXPECT_FALSE(task_runner->HasPendingTask());
    414 
    415   controller->SetUpdateTextureTime(base::TimeDelta::FromMilliseconds(100));
    416   controller->SetUpdateMoreTexturesSize(1);
    417   // Only enough time for 1 update.
    418   controller->PerformMoreUpdates(controller->Now() +
    419                                  base::TimeDelta::FromMilliseconds(120));
    420   EXPECT_FALSE(task_runner->HasPendingTask());
    421   EXPECT_EQ(1, num_total_uploads_);
    422 
    423   // Complete one upload.
    424   MakeQueryResultAvailable();
    425 
    426   controller->SetUpdateTextureTime(base::TimeDelta::FromMilliseconds(100));
    427   controller->SetUpdateMoreTexturesSize(1);
    428   // Enough time for 2 updates.
    429   controller->PerformMoreUpdates(controller->Now() +
    430                                  base::TimeDelta::FromMilliseconds(220));
    431   RunPendingTask(task_runner.get(), controller.get());
    432   EXPECT_FALSE(task_runner->HasPendingTask());
    433   EXPECT_TRUE(client.ReadyToFinalizeCalled());
    434   EXPECT_EQ(3, num_total_uploads_);
    435 }
    436 
    437 TEST_F(ResourceUpdateControllerTest, NoMoreUpdates) {
    438   FakeResourceUpdateControllerClient client;
    439   scoped_refptr<base::TestSimpleTaskRunner> task_runner =
    440       new base::TestSimpleTaskRunner;
    441 
    442   SetMaxUploadCountPerUpdate(1);
    443   AppendFullUploadsToUpdateQueue(2);
    444   AppendPartialUploadsToUpdateQueue(0);
    445 
    446   DebugScopedSetImplThreadAndMainThreadBlocked
    447   impl_thread_and_main_thread_blocked(&proxy_);
    448   scoped_ptr<FakeResourceUpdateController> controller(
    449       FakeResourceUpdateController::Create(&client,
    450                                            task_runner.get(),
    451                                            queue_.Pass(),
    452                                            resource_provider_.get()));
    453 
    454   controller->SetNow(controller->Now() + base::TimeDelta::FromMilliseconds(1));
    455   controller->SetUpdateTextureTime(base::TimeDelta::FromMilliseconds(100));
    456   controller->SetUpdateMoreTexturesSize(1);
    457   // Enough time for 3 updates but only 2 necessary.
    458   controller->PerformMoreUpdates(controller->Now() +
    459                                  base::TimeDelta::FromMilliseconds(310));
    460   RunPendingTask(task_runner.get(), controller.get());
    461   EXPECT_FALSE(task_runner->HasPendingTask());
    462   EXPECT_TRUE(client.ReadyToFinalizeCalled());
    463   EXPECT_EQ(2, num_total_uploads_);
    464 
    465   client.Reset();
    466   controller->SetUpdateTextureTime(base::TimeDelta::FromMilliseconds(100));
    467   controller->SetUpdateMoreTexturesSize(1);
    468   // Enough time for updates but no more updates left.
    469   controller->PerformMoreUpdates(controller->Now() +
    470                                  base::TimeDelta::FromMilliseconds(310));
    471 
    472   // ReadyToFinalizeTextureUpdates should only be called once.
    473   EXPECT_FALSE(task_runner->HasPendingTask());
    474   EXPECT_FALSE(client.ReadyToFinalizeCalled());
    475   EXPECT_EQ(2, num_total_uploads_);
    476 }
    477 
    478 TEST_F(ResourceUpdateControllerTest, UpdatesCompleteInFiniteTime) {
    479   FakeResourceUpdateControllerClient client;
    480   scoped_refptr<base::TestSimpleTaskRunner> task_runner =
    481       new base::TestSimpleTaskRunner;
    482 
    483   SetMaxUploadCountPerUpdate(1);
    484   AppendFullUploadsToUpdateQueue(2);
    485   AppendPartialUploadsToUpdateQueue(0);
    486 
    487   DebugScopedSetImplThreadAndMainThreadBlocked
    488   impl_thread_and_main_thread_blocked(&proxy_);
    489   scoped_ptr<FakeResourceUpdateController> controller(
    490       FakeResourceUpdateController::Create(&client,
    491                                            task_runner.get(),
    492                                            queue_.Pass(),
    493                                            resource_provider_.get()));
    494 
    495   controller->SetNow(controller->Now() + base::TimeDelta::FromMilliseconds(1));
    496   controller->SetUpdateTextureTime(base::TimeDelta::FromMilliseconds(500));
    497   controller->SetUpdateMoreTexturesSize(1);
    498 
    499   for (int i = 0; i < 100; i++) {
    500     if (client.ReadyToFinalizeCalled())
    501       break;
    502 
    503     // Not enough time for any updates.
    504     controller->PerformMoreUpdates(controller->Now() +
    505                                    base::TimeDelta::FromMilliseconds(400));
    506 
    507     if (task_runner->HasPendingTask())
    508       RunPendingTask(task_runner.get(), controller.get());
    509   }
    510 
    511   EXPECT_FALSE(task_runner->HasPendingTask());
    512   EXPECT_TRUE(client.ReadyToFinalizeCalled());
    513   EXPECT_EQ(2, num_total_uploads_);
    514 }
    515 
    516 }  // namespace
    517 }  // namespace cc
    518