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