- add sources.
[platform/framework/web/crosswalk.git] / src / cc / resources / resource_update_controller_unittest.cc
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 using WebKit::WGC3Denum;
21 using WebKit::WGC3Dint;
22 using WebKit::WGC3Duint;
23 using WebKit::WGC3Dsizei;
24 using WebKit::WebGLId;
25 using WebKit::WebString;
26
27 namespace cc {
28 namespace {
29
30 const int kFlushPeriodFull = 4;
31 const int kFlushPeriodPartial = kFlushPeriodFull;
32
33 class ResourceUpdateControllerTest;
34
35 class WebGraphicsContext3DForUploadTest : public TestWebGraphicsContext3D {
36  public:
37   explicit WebGraphicsContext3DForUploadTest(ResourceUpdateControllerTest* test)
38       : test_(test) {
39     test_capabilities_.shallow_flush = true;
40   }
41
42   virtual void flush() OVERRIDE;
43   virtual void shallowFlushCHROMIUM() OVERRIDE;
44   virtual void texSubImage2D(
45       WGC3Denum target,
46       WGC3Dint level,
47       WGC3Dint xoffset,
48       WGC3Dint yoffset,
49       WGC3Dsizei width,
50       WGC3Dsizei height,
51       WGC3Denum format,
52       WGC3Denum type,
53       const void* pixels) OVERRIDE;
54   virtual GrGLInterface* createGrGLInterface() OVERRIDE { return NULL; }
55
56   virtual void getQueryObjectuivEXT(
57       WebGLId id,
58       WGC3Denum pname,
59       WGC3Duint* value);
60
61  private:
62   ResourceUpdateControllerTest* test_;
63 };
64
65 class ResourceUpdateControllerTest : public Test {
66  public:
67   ResourceUpdateControllerTest()
68       : proxy_(),
69         queue_(make_scoped_ptr(new ResourceUpdateQueue)),
70         resource_manager_(PrioritizedResourceManager::Create(&proxy_)),
71         query_results_available_(0),
72         full_upload_count_expected_(0),
73         partial_count_expected_(0),
74         total_upload_count_expected_(0),
75         max_upload_count_per_update_(0),
76         num_consecutive_flushes_(0),
77         num_dangling_uploads_(0),
78         num_total_uploads_(0),
79         num_total_flushes_(0) {}
80
81   virtual ~ResourceUpdateControllerTest() {
82     DebugScopedSetImplThreadAndMainThreadBlocked
83     impl_thread_and_main_thread_blocked(&proxy_);
84     resource_manager_->ClearAllMemory(resource_provider_.get());
85   }
86
87  public:
88   void OnFlush() {
89     // Check for back-to-back flushes.
90     EXPECT_EQ(0, num_consecutive_flushes_) << "Back-to-back flushes detected.";
91
92     num_dangling_uploads_ = 0;
93     num_consecutive_flushes_++;
94     num_total_flushes_++;
95   }
96
97   void OnUpload() {
98     // Check for too many consecutive uploads
99     if (num_total_uploads_ < full_upload_count_expected_) {
100       EXPECT_LT(num_dangling_uploads_, kFlushPeriodFull)
101           << "Too many consecutive full uploads detected.";
102     } else {
103       EXPECT_LT(num_dangling_uploads_, kFlushPeriodPartial)
104           << "Too many consecutive partial uploads detected.";
105     }
106
107     num_consecutive_flushes_ = 0;
108     num_dangling_uploads_++;
109     num_total_uploads_++;
110   }
111
112   bool IsQueryResultAvailable() {
113     if (!query_results_available_)
114       return false;
115
116     query_results_available_--;
117     return true;
118   }
119
120  protected:
121   virtual void SetUp() {
122     bitmap_.setConfig(SkBitmap::kARGB_8888_Config, 300, 150);
123     bitmap_.allocPixels();
124
125     for (int i = 0; i < 4; i++) {
126       textures_[i] = PrioritizedResource::Create(resource_manager_.get(),
127                                                  gfx::Size(300, 150),
128                                                  RGBA_8888);
129       textures_[i]->
130           set_request_priority(PriorityCalculator::VisiblePriority(true));
131     }
132     resource_manager_->PrioritizeTextures();
133
134     output_surface_ = FakeOutputSurface::Create3d(
135         scoped_ptr<TestWebGraphicsContext3D>(
136             new WebGraphicsContext3DForUploadTest(this)));
137     CHECK(output_surface_->BindToClient(&output_surface_client_));
138
139     resource_provider_ =
140         ResourceProvider::Create(output_surface_.get(), NULL, 0, false, 1);
141   }
142
143   void AppendFullUploadsOfIndexedTextureToUpdateQueue(int count,
144                                                       int texture_index) {
145     full_upload_count_expected_ += count;
146     total_upload_count_expected_ += count;
147
148     const gfx::Rect rect(0, 0, 300, 150);
149     const ResourceUpdate upload = ResourceUpdate::Create(
150         textures_[texture_index].get(), &bitmap_, rect, rect, gfx::Vector2d());
151     for (int i = 0; i < count; i++)
152       queue_->AppendFullUpload(upload);
153   }
154
155   void AppendFullUploadsToUpdateQueue(int count) {
156     AppendFullUploadsOfIndexedTextureToUpdateQueue(count, 0);
157   }
158
159   void AppendPartialUploadsOfIndexedTextureToUpdateQueue(int count,
160                                                          int texture_index) {
161     partial_count_expected_ += count;
162     total_upload_count_expected_ += count;
163
164     const gfx::Rect rect(0, 0, 100, 100);
165     const ResourceUpdate upload = ResourceUpdate::Create(
166         textures_[texture_index].get(), &bitmap_, rect, rect, gfx::Vector2d());
167     for (int i = 0; i < count; i++)
168       queue_->AppendPartialUpload(upload);
169   }
170
171   void AppendPartialUploadsToUpdateQueue(int count) {
172     AppendPartialUploadsOfIndexedTextureToUpdateQueue(count, 0);
173   }
174
175   void SetMaxUploadCountPerUpdate(int count) {
176     max_upload_count_per_update_ = count;
177   }
178
179   void UpdateTextures() {
180     DebugScopedSetImplThreadAndMainThreadBlocked
181     impl_thread_and_main_thread_blocked(&proxy_);
182     scoped_ptr<ResourceUpdateController> update_controller =
183         ResourceUpdateController::Create(NULL,
184                                          proxy_.ImplThreadTaskRunner(),
185                                          queue_.Pass(),
186                                          resource_provider_.get());
187     update_controller->Finalize();
188   }
189
190   void MakeQueryResultAvailable() { query_results_available_++; }
191
192  protected:
193   // Classes required to interact and test the ResourceUpdateController
194   FakeProxy proxy_;
195   FakeOutputSurfaceClient output_surface_client_;
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() { test_->OnFlush(); }
218
219 void WebGraphicsContext3DForUploadTest::shallowFlushCHROMIUM() {
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