GPU workaround to simulate Out of Memory errors with large textures
[chromium-blink-merge.git] / cc / resources / resource_update_controller_unittest.cc
blob1aa0902d469932c0ea6eb4c2598574c4c40ae666
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.
5 #include "cc/resources/resource_update_controller.h"
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"
20 using testing::Test;
22 namespace cc {
23 namespace {
25 const int kFlushPeriodFull = 4;
26 const int kFlushPeriodPartial = kFlushPeriodFull;
28 class ResourceUpdateControllerTest;
30 class WebGraphicsContext3DForUploadTest : public TestWebGraphicsContext3D {
31 public:
32 explicit WebGraphicsContext3DForUploadTest(ResourceUpdateControllerTest* test)
33 : test_(test) {}
35 void flush() override;
36 void shallowFlushCHROMIUM() override;
37 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;
47 void getQueryObjectuivEXT(GLuint id, GLenum pname, GLuint* value) override;
49 private:
50 ResourceUpdateControllerTest* test_;
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) {}
69 ~ResourceUpdateControllerTest() override {
70 DebugScopedSetImplThreadAndMainThreadBlocked
71 impl_thread_and_main_thread_blocked(&proxy_);
72 resource_manager_->ClearAllMemory(resource_provider_.get());
75 public:
76 void OnFlush() {
77 // Check for back-to-back flushes.
78 EXPECT_EQ(0, num_consecutive_flushes_) << "Back-to-back flushes detected.";
80 num_dangling_uploads_ = 0;
81 num_consecutive_flushes_++;
82 num_total_flushes_++;
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.";
95 num_consecutive_flushes_ = 0;
96 num_dangling_uploads_++;
97 num_total_uploads_++;
100 bool IsQueryResultAvailable() {
101 if (!query_results_available_)
102 return false;
104 query_results_available_--;
105 return true;
108 protected:
109 void SetUp() override {
110 bitmap_.allocN32Pixels(300, 150);
112 for (int i = 0; i < 4; i++) {
113 textures_[i] = PrioritizedResource::Create(resource_manager_.get(),
114 gfx::Size(300, 150),
115 RGBA_8888);
116 textures_[i]->
117 set_request_priority(PriorityCalculator::VisiblePriority(true));
119 resource_manager_->PrioritizeTextures();
121 output_surface_ = FakeOutputSurface::Create3d(
122 scoped_ptr<TestWebGraphicsContext3D>(
123 new WebGraphicsContext3DForUploadTest(this)));
124 CHECK(output_surface_->BindToClient(&output_surface_client_));
126 shared_bitmap_manager_.reset(new TestSharedBitmapManager());
127 resource_provider_ = ResourceProvider::Create(output_surface_.get(),
128 shared_bitmap_manager_.get(),
129 NULL,
130 NULL,
132 false,
136 void AppendFullUploadsOfIndexedTextureToUpdateQueue(int count,
137 int texture_index) {
138 full_upload_count_expected_ += count;
139 total_upload_count_expected_ += count;
141 const gfx::Rect rect(0, 0, 300, 150);
142 const ResourceUpdate upload = ResourceUpdate::Create(
143 textures_[texture_index].get(), &bitmap_, rect, rect, gfx::Vector2d());
144 for (int i = 0; i < count; i++)
145 queue_->AppendFullUpload(upload);
148 void AppendFullUploadsToUpdateQueue(int count) {
149 AppendFullUploadsOfIndexedTextureToUpdateQueue(count, 0);
152 void AppendPartialUploadsOfIndexedTextureToUpdateQueue(int count,
153 int texture_index) {
154 partial_count_expected_ += count;
155 total_upload_count_expected_ += count;
157 const gfx::Rect rect(0, 0, 100, 100);
158 const ResourceUpdate upload = ResourceUpdate::Create(
159 textures_[texture_index].get(), &bitmap_, rect, rect, gfx::Vector2d());
160 for (int i = 0; i < count; i++)
161 queue_->AppendPartialUpload(upload);
164 void AppendPartialUploadsToUpdateQueue(int count) {
165 AppendPartialUploadsOfIndexedTextureToUpdateQueue(count, 0);
168 void SetMaxUploadCountPerUpdate(int count) {
169 max_upload_count_per_update_ = count;
172 void UpdateTextures() {
173 DebugScopedSetImplThreadAndMainThreadBlocked
174 impl_thread_and_main_thread_blocked(&proxy_);
175 scoped_ptr<ResourceUpdateController> update_controller =
176 ResourceUpdateController::Create(NULL,
177 proxy_.ImplThreadTaskRunner(),
178 queue_.Pass(),
179 resource_provider_.get());
180 update_controller->Finalize();
183 void MakeQueryResultAvailable() { query_results_available_++; }
185 protected:
186 // Classes required to interact and test the ResourceUpdateController
187 FakeProxy proxy_;
188 FakeOutputSurfaceClient output_surface_client_;
189 scoped_ptr<OutputSurface> output_surface_;
190 scoped_ptr<SharedBitmapManager> shared_bitmap_manager_;
191 scoped_ptr<ResourceProvider> resource_provider_;
192 scoped_ptr<ResourceUpdateQueue> queue_;
193 scoped_ptr<PrioritizedResource> textures_[4];
194 scoped_ptr<PrioritizedResourceManager> resource_manager_;
195 SkBitmap bitmap_;
196 int query_results_available_;
198 // Properties / expectations of this test
199 int full_upload_count_expected_;
200 int partial_count_expected_;
201 int total_upload_count_expected_;
202 int max_upload_count_per_update_;
204 // Dynamic properties of this test
205 int num_consecutive_flushes_;
206 int num_dangling_uploads_;
207 int num_total_uploads_;
208 int num_total_flushes_;
211 void WebGraphicsContext3DForUploadTest::flush() { test_->OnFlush(); }
213 void WebGraphicsContext3DForUploadTest::shallowFlushCHROMIUM() {
214 test_->OnFlush();
217 void WebGraphicsContext3DForUploadTest::texSubImage2D(GLenum target,
218 GLint level,
219 GLint xoffset,
220 GLint yoffset,
221 GLsizei width,
222 GLsizei height,
223 GLenum format,
224 GLenum type,
225 const void* pixels) {
226 test_->OnUpload();
229 void WebGraphicsContext3DForUploadTest::getQueryObjectuivEXT(GLuint id,
230 GLenum pname,
231 GLuint* params) {
232 if (pname == GL_QUERY_RESULT_AVAILABLE_EXT)
233 *params = test_->IsQueryResultAvailable();
236 // ZERO UPLOADS TESTS
237 TEST_F(ResourceUpdateControllerTest, ZeroUploads) {
238 AppendFullUploadsToUpdateQueue(0);
239 AppendPartialUploadsToUpdateQueue(0);
240 UpdateTextures();
242 EXPECT_EQ(0, num_total_flushes_);
243 EXPECT_EQ(0, num_total_uploads_);
246 // ONE UPLOAD TESTS
247 TEST_F(ResourceUpdateControllerTest, OneFullUpload) {
248 AppendFullUploadsToUpdateQueue(1);
249 AppendPartialUploadsToUpdateQueue(0);
250 UpdateTextures();
252 EXPECT_EQ(1, num_total_flushes_);
253 EXPECT_EQ(1, num_total_uploads_);
254 EXPECT_EQ(0, num_dangling_uploads_)
255 << "Last upload wasn't followed by a flush.";
258 TEST_F(ResourceUpdateControllerTest, OnePartialUpload) {
259 AppendFullUploadsToUpdateQueue(0);
260 AppendPartialUploadsToUpdateQueue(1);
261 UpdateTextures();
263 EXPECT_EQ(1, num_total_flushes_);
264 EXPECT_EQ(1, num_total_uploads_);
265 EXPECT_EQ(0, num_dangling_uploads_)
266 << "Last upload wasn't followed by a flush.";
269 TEST_F(ResourceUpdateControllerTest, OneFullOnePartialUpload) {
270 AppendFullUploadsToUpdateQueue(1);
271 AppendPartialUploadsToUpdateQueue(1);
272 UpdateTextures();
274 EXPECT_EQ(1, num_total_flushes_);
275 EXPECT_EQ(2, num_total_uploads_);
276 EXPECT_EQ(0, num_dangling_uploads_)
277 << "Last upload wasn't followed by a flush.";
280 // This class of tests upload a number of textures that is a multiple
281 // of the flush period.
282 const int full_upload_flush_multipler = 7;
283 const int full_count = full_upload_flush_multipler * kFlushPeriodFull;
285 const int partial_upload_flush_multipler = 11;
286 const int partial_count =
287 partial_upload_flush_multipler * kFlushPeriodPartial;
289 TEST_F(ResourceUpdateControllerTest, ManyFullUploads) {
290 AppendFullUploadsToUpdateQueue(full_count);
291 AppendPartialUploadsToUpdateQueue(0);
292 UpdateTextures();
294 EXPECT_EQ(full_upload_flush_multipler, num_total_flushes_);
295 EXPECT_EQ(full_count, num_total_uploads_);
296 EXPECT_EQ(0, num_dangling_uploads_)
297 << "Last upload wasn't followed by a flush.";
300 TEST_F(ResourceUpdateControllerTest, ManyPartialUploads) {
301 AppendFullUploadsToUpdateQueue(0);
302 AppendPartialUploadsToUpdateQueue(partial_count);
303 UpdateTextures();
305 EXPECT_EQ(partial_upload_flush_multipler, num_total_flushes_);
306 EXPECT_EQ(partial_count, num_total_uploads_);
307 EXPECT_EQ(0, num_dangling_uploads_)
308 << "Last upload wasn't followed by a flush.";
311 TEST_F(ResourceUpdateControllerTest, ManyFullManyPartialUploads) {
312 AppendFullUploadsToUpdateQueue(full_count);
313 AppendPartialUploadsToUpdateQueue(partial_count);
314 UpdateTextures();
316 EXPECT_EQ(full_upload_flush_multipler + partial_upload_flush_multipler,
317 num_total_flushes_);
318 EXPECT_EQ(full_count + partial_count, num_total_uploads_);
319 EXPECT_EQ(0, num_dangling_uploads_)
320 << "Last upload wasn't followed by a flush.";
323 class FakeResourceUpdateControllerClient
324 : public ResourceUpdateControllerClient {
325 public:
326 FakeResourceUpdateControllerClient() { Reset(); }
327 void Reset() { ready_to_finalize_called_ = false; }
328 bool ReadyToFinalizeCalled() const { return ready_to_finalize_called_; }
330 void ReadyToFinalizeTextureUpdates() override {
331 ready_to_finalize_called_ = true;
334 protected:
335 bool ready_to_finalize_called_;
338 class FakeResourceUpdateController : public ResourceUpdateController {
339 public:
340 static scoped_ptr<FakeResourceUpdateController> Create(
341 ResourceUpdateControllerClient* client,
342 base::TestSimpleTaskRunner* task_runner,
343 scoped_ptr<ResourceUpdateQueue> queue,
344 ResourceProvider* resource_provider) {
345 return make_scoped_ptr(new FakeResourceUpdateController(
346 client, task_runner, queue.Pass(), resource_provider));
349 void SetNow(base::TimeTicks time) { now_ = time; }
350 base::TimeTicks Now() const { return now_; }
351 void SetUpdateTextureTime(base::TimeDelta time) {
352 update_textures_time_ = time;
354 base::TimeTicks UpdateMoreTexturesCompletionTime() override {
355 size_t total_updates =
356 resource_provider_->NumBlockingUploads() + update_more_textures_size_;
357 return now_ + total_updates * update_textures_time_;
359 void SetUpdateMoreTexturesSize(size_t size) {
360 update_more_textures_size_ = size;
362 size_t UpdateMoreTexturesSize() const override {
363 return update_more_textures_size_;
366 protected:
367 FakeResourceUpdateController(ResourceUpdateControllerClient* client,
368 base::TestSimpleTaskRunner* task_runner,
369 scoped_ptr<ResourceUpdateQueue> queue,
370 ResourceProvider* resource_provider)
371 : ResourceUpdateController(
372 client, task_runner, queue.Pass(), resource_provider),
373 resource_provider_(resource_provider),
374 update_more_textures_size_(0) {}
376 ResourceProvider* resource_provider_;
377 base::TimeTicks now_;
378 base::TimeDelta update_textures_time_;
379 size_t update_more_textures_size_;
382 static void RunPendingTask(base::TestSimpleTaskRunner* task_runner,
383 FakeResourceUpdateController* controller) {
384 EXPECT_TRUE(task_runner->HasPendingTask());
385 controller->SetNow(controller->Now() + task_runner->NextPendingTaskDelay());
386 task_runner->RunPendingTasks();
389 TEST_F(ResourceUpdateControllerTest, UpdateMoreTextures) {
390 FakeResourceUpdateControllerClient client;
391 scoped_refptr<base::TestSimpleTaskRunner> task_runner =
392 new base::TestSimpleTaskRunner;
394 SetMaxUploadCountPerUpdate(1);
395 AppendFullUploadsToUpdateQueue(3);
396 AppendPartialUploadsToUpdateQueue(0);
398 DebugScopedSetImplThreadAndMainThreadBlocked
399 impl_thread_and_main_thread_blocked(&proxy_);
400 scoped_ptr<FakeResourceUpdateController> controller(
401 FakeResourceUpdateController::Create(&client,
402 task_runner.get(),
403 queue_.Pass(),
404 resource_provider_.get()));
406 controller->SetNow(controller->Now() + base::TimeDelta::FromMilliseconds(1));
407 controller->SetUpdateTextureTime(base::TimeDelta::FromMilliseconds(100));
408 controller->SetUpdateMoreTexturesSize(1);
409 // Not enough time for any updates.
410 controller->PerformMoreUpdates(controller->Now() +
411 base::TimeDelta::FromMilliseconds(90));
412 EXPECT_FALSE(task_runner->HasPendingTask());
414 controller->SetUpdateTextureTime(base::TimeDelta::FromMilliseconds(100));
415 controller->SetUpdateMoreTexturesSize(1);
416 // Only enough time for 1 update.
417 controller->PerformMoreUpdates(controller->Now() +
418 base::TimeDelta::FromMilliseconds(120));
419 EXPECT_FALSE(task_runner->HasPendingTask());
420 EXPECT_EQ(1, num_total_uploads_);
422 // Complete one upload.
423 MakeQueryResultAvailable();
425 controller->SetUpdateTextureTime(base::TimeDelta::FromMilliseconds(100));
426 controller->SetUpdateMoreTexturesSize(1);
427 // Enough time for 2 updates.
428 controller->PerformMoreUpdates(controller->Now() +
429 base::TimeDelta::FromMilliseconds(220));
430 RunPendingTask(task_runner.get(), controller.get());
431 EXPECT_FALSE(task_runner->HasPendingTask());
432 EXPECT_TRUE(client.ReadyToFinalizeCalled());
433 EXPECT_EQ(3, num_total_uploads_);
436 TEST_F(ResourceUpdateControllerTest, NoMoreUpdates) {
437 FakeResourceUpdateControllerClient client;
438 scoped_refptr<base::TestSimpleTaskRunner> task_runner =
439 new base::TestSimpleTaskRunner;
441 SetMaxUploadCountPerUpdate(1);
442 AppendFullUploadsToUpdateQueue(2);
443 AppendPartialUploadsToUpdateQueue(0);
445 DebugScopedSetImplThreadAndMainThreadBlocked
446 impl_thread_and_main_thread_blocked(&proxy_);
447 scoped_ptr<FakeResourceUpdateController> controller(
448 FakeResourceUpdateController::Create(&client,
449 task_runner.get(),
450 queue_.Pass(),
451 resource_provider_.get()));
453 controller->SetNow(controller->Now() + base::TimeDelta::FromMilliseconds(1));
454 controller->SetUpdateTextureTime(base::TimeDelta::FromMilliseconds(100));
455 controller->SetUpdateMoreTexturesSize(1);
456 // Enough time for 3 updates but only 2 necessary.
457 controller->PerformMoreUpdates(controller->Now() +
458 base::TimeDelta::FromMilliseconds(310));
459 RunPendingTask(task_runner.get(), controller.get());
460 EXPECT_FALSE(task_runner->HasPendingTask());
461 EXPECT_TRUE(client.ReadyToFinalizeCalled());
462 EXPECT_EQ(2, num_total_uploads_);
464 client.Reset();
465 controller->SetUpdateTextureTime(base::TimeDelta::FromMilliseconds(100));
466 controller->SetUpdateMoreTexturesSize(1);
467 // Enough time for updates but no more updates left.
468 controller->PerformMoreUpdates(controller->Now() +
469 base::TimeDelta::FromMilliseconds(310));
471 // ReadyToFinalizeTextureUpdates should only be called once.
472 EXPECT_FALSE(task_runner->HasPendingTask());
473 EXPECT_FALSE(client.ReadyToFinalizeCalled());
474 EXPECT_EQ(2, num_total_uploads_);
477 TEST_F(ResourceUpdateControllerTest, UpdatesCompleteInFiniteTime) {
478 FakeResourceUpdateControllerClient client;
479 scoped_refptr<base::TestSimpleTaskRunner> task_runner =
480 new base::TestSimpleTaskRunner;
482 SetMaxUploadCountPerUpdate(1);
483 AppendFullUploadsToUpdateQueue(2);
484 AppendPartialUploadsToUpdateQueue(0);
486 DebugScopedSetImplThreadAndMainThreadBlocked
487 impl_thread_and_main_thread_blocked(&proxy_);
488 scoped_ptr<FakeResourceUpdateController> controller(
489 FakeResourceUpdateController::Create(&client,
490 task_runner.get(),
491 queue_.Pass(),
492 resource_provider_.get()));
494 controller->SetNow(controller->Now() + base::TimeDelta::FromMilliseconds(1));
495 controller->SetUpdateTextureTime(base::TimeDelta::FromMilliseconds(500));
496 controller->SetUpdateMoreTexturesSize(1);
498 for (int i = 0; i < 100; i++) {
499 if (client.ReadyToFinalizeCalled())
500 break;
502 // Not enough time for any updates.
503 controller->PerformMoreUpdates(controller->Now() +
504 base::TimeDelta::FromMilliseconds(400));
506 if (task_runner->HasPendingTask())
507 RunPendingTask(task_runner.get(), controller.get());
510 EXPECT_FALSE(task_runner->HasPendingTask());
511 EXPECT_TRUE(client.ReadyToFinalizeCalled());
512 EXPECT_EQ(2, num_total_uploads_);
515 } // namespace
516 } // namespace cc