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