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