Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / cc / raster / tile_task_worker_pool_unittest.cc
blobd8e0d19090b510b9d33117e23e4569f748372fab
1 // Copyright 2013 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/raster/tile_task_worker_pool.h"
7 #include <limits>
8 #include <vector>
10 #include "base/cancelable_callback.h"
11 #include "base/location.h"
12 #include "base/single_thread_task_runner.h"
13 #include "base/thread_task_runner_handle.h"
14 #include "cc/base/unique_notifier.h"
15 #include "cc/playback/picture_pile.h"
16 #include "cc/playback/picture_pile_impl.h"
17 #include "cc/raster/bitmap_tile_task_worker_pool.h"
18 #include "cc/raster/gpu_rasterizer.h"
19 #include "cc/raster/gpu_tile_task_worker_pool.h"
20 #include "cc/raster/one_copy_tile_task_worker_pool.h"
21 #include "cc/raster/raster_buffer.h"
22 #include "cc/raster/tile_task_runner.h"
23 #include "cc/raster/zero_copy_tile_task_worker_pool.h"
24 #include "cc/resources/resource_pool.h"
25 #include "cc/resources/resource_provider.h"
26 #include "cc/resources/scoped_resource.h"
27 #include "cc/test/fake_output_surface.h"
28 #include "cc/test/fake_output_surface_client.h"
29 #include "cc/test/fake_picture_pile_impl.h"
30 #include "cc/test/fake_resource_provider.h"
31 #include "cc/test/test_gpu_memory_buffer_manager.h"
32 #include "cc/test/test_shared_bitmap_manager.h"
33 #include "cc/test/test_task_graph_runner.h"
34 #include "cc/test/test_web_graphics_context_3d.h"
35 #include "gpu/GLES2/gl2extchromium.h"
36 #include "testing/gtest/include/gtest/gtest.h"
38 namespace cc {
39 namespace {
41 const size_t kMaxBytesPerCopyOperation = 1000U;
42 const size_t kMaxStagingBuffers = 32U;
44 enum TileTaskWorkerPoolType {
45 TILE_TASK_WORKER_POOL_TYPE_ZERO_COPY,
46 TILE_TASK_WORKER_POOL_TYPE_ONE_COPY,
47 TILE_TASK_WORKER_POOL_TYPE_GPU,
48 TILE_TASK_WORKER_POOL_TYPE_BITMAP
51 class TestRasterTaskImpl : public RasterTask {
52 public:
53 typedef base::Callback<void(const RasterSource::SolidColorAnalysis& analysis,
54 bool was_canceled)> Reply;
56 TestRasterTaskImpl(const Resource* resource,
57 const Reply& reply,
58 ImageDecodeTask::Vector* dependencies)
59 : RasterTask(dependencies),
60 resource_(resource),
61 reply_(reply),
62 picture_pile_(FakePicturePileImpl::CreateEmptyPile(gfx::Size(1, 1),
63 gfx::Size(1, 1))) {}
65 // Overridden from Task:
66 void RunOnWorkerThread() override {
67 uint64_t new_content_id = 0;
68 raster_buffer_->Playback(picture_pile_.get(), gfx::Rect(1, 1),
69 gfx::Rect(1, 1), new_content_id, 1.f, true);
72 // Overridden from TileTask:
73 void ScheduleOnOriginThread(TileTaskClient* client) override {
74 // The raster buffer has no tile ids associated with it for partial update,
75 // so doesn't need to provide a valid dirty rect.
76 raster_buffer_ = client->AcquireBufferForRaster(resource_, 0, 0);
78 void CompleteOnOriginThread(TileTaskClient* client) override {
79 client->ReleaseBufferForRaster(raster_buffer_.Pass());
80 reply_.Run(RasterSource::SolidColorAnalysis(), !HasFinishedRunning());
83 protected:
84 ~TestRasterTaskImpl() override {}
86 private:
87 const Resource* resource_;
88 const Reply reply_;
89 scoped_ptr<RasterBuffer> raster_buffer_;
90 scoped_refptr<PicturePileImpl> picture_pile_;
92 DISALLOW_COPY_AND_ASSIGN(TestRasterTaskImpl);
95 class BlockingTestRasterTaskImpl : public TestRasterTaskImpl {
96 public:
97 BlockingTestRasterTaskImpl(const Resource* resource,
98 const Reply& reply,
99 base::Lock* lock,
100 ImageDecodeTask::Vector* dependencies)
101 : TestRasterTaskImpl(resource, reply, dependencies), lock_(lock) {}
103 // Overridden from Task:
104 void RunOnWorkerThread() override {
105 base::AutoLock lock(*lock_);
106 TestRasterTaskImpl::RunOnWorkerThread();
109 protected:
110 ~BlockingTestRasterTaskImpl() override {}
112 private:
113 base::Lock* lock_;
115 DISALLOW_COPY_AND_ASSIGN(BlockingTestRasterTaskImpl);
118 class TileTaskWorkerPoolTest
119 : public testing::TestWithParam<TileTaskWorkerPoolType>,
120 public TileTaskRunnerClient {
121 public:
122 struct RasterTaskResult {
123 unsigned id;
124 bool canceled;
127 typedef std::vector<scoped_refptr<RasterTask>> RasterTaskVector;
129 enum NamedTaskSet { REQUIRED_FOR_ACTIVATION, REQUIRED_FOR_DRAW, ALL };
131 TileTaskWorkerPoolTest()
132 : context_provider_(TestContextProvider::Create()),
133 worker_context_provider_(TestContextProvider::Create()),
134 all_tile_tasks_finished_(
135 base::ThreadTaskRunnerHandle::Get().get(),
136 base::Bind(&TileTaskWorkerPoolTest::AllTileTasksFinished,
137 base::Unretained(this))),
138 timeout_seconds_(5),
139 timed_out_(false) {}
141 // Overridden from testing::Test:
142 void SetUp() override {
143 switch (GetParam()) {
144 case TILE_TASK_WORKER_POOL_TYPE_ZERO_COPY:
145 Create3dOutputSurfaceAndResourceProvider();
146 tile_task_worker_pool_ = ZeroCopyTileTaskWorkerPool::Create(
147 base::ThreadTaskRunnerHandle::Get().get(), &task_graph_runner_,
148 resource_provider_.get());
149 break;
150 case TILE_TASK_WORKER_POOL_TYPE_ONE_COPY:
151 Create3dOutputSurfaceAndResourceProvider();
152 tile_task_worker_pool_ = OneCopyTileTaskWorkerPool::Create(
153 base::ThreadTaskRunnerHandle::Get().get(), &task_graph_runner_,
154 context_provider_.get(), resource_provider_.get(),
155 kMaxBytesPerCopyOperation, false, kMaxStagingBuffers);
156 break;
157 case TILE_TASK_WORKER_POOL_TYPE_GPU:
158 Create3dOutputSurfaceAndResourceProvider();
159 tile_task_worker_pool_ = GpuTileTaskWorkerPool::Create(
160 base::ThreadTaskRunnerHandle::Get().get(), &task_graph_runner_,
161 context_provider_.get(), resource_provider_.get(), false, 0);
162 break;
163 case TILE_TASK_WORKER_POOL_TYPE_BITMAP:
164 CreateSoftwareOutputSurfaceAndResourceProvider();
165 tile_task_worker_pool_ = BitmapTileTaskWorkerPool::Create(
166 base::ThreadTaskRunnerHandle::Get().get(), &task_graph_runner_,
167 resource_provider_.get());
168 break;
171 DCHECK(tile_task_worker_pool_);
172 tile_task_worker_pool_->AsTileTaskRunner()->SetClient(this);
175 void TearDown() override {
176 tile_task_worker_pool_->AsTileTaskRunner()->Shutdown();
177 tile_task_worker_pool_->AsTileTaskRunner()->CheckForCompletedTasks();
180 void AllTileTasksFinished() {
181 tile_task_worker_pool_->AsTileTaskRunner()->CheckForCompletedTasks();
182 base::MessageLoop::current()->Quit();
185 // Overriden from TileTaskWorkerPoolClient:
186 void DidFinishRunningTileTasks(TaskSet task_set) override {
187 EXPECT_FALSE(completed_task_sets_[task_set]);
188 completed_task_sets_[task_set] = true;
189 if (task_set == ALL) {
190 EXPECT_TRUE((~completed_task_sets_).none());
191 all_tile_tasks_finished_.Schedule();
195 void RunMessageLoopUntilAllTasksHaveCompleted() {
196 if (timeout_seconds_) {
197 timeout_.Reset(base::Bind(&TileTaskWorkerPoolTest::OnTimeout,
198 base::Unretained(this)));
199 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
200 FROM_HERE, timeout_.callback(),
201 base::TimeDelta::FromSeconds(timeout_seconds_));
204 base::MessageLoop::current()->Run();
206 timeout_.Cancel();
208 ASSERT_FALSE(timed_out_) << "Test timed out";
211 void ScheduleTasks() {
212 TileTaskQueue queue;
214 for (RasterTaskVector::const_iterator it = tasks_.begin();
215 it != tasks_.end(); ++it) {
216 TaskSetCollection task_sets;
217 task_sets[REQUIRED_FOR_ACTIVATION] = true;
218 task_sets[REQUIRED_FOR_DRAW] = true;
219 task_sets[ALL] = true;
220 queue.items.push_back(TileTaskQueue::Item(it->get(), task_sets));
223 completed_task_sets_.reset();
224 tile_task_worker_pool_->AsTileTaskRunner()->ScheduleTasks(&queue);
227 void AppendTask(unsigned id, const gfx::Size& size) {
228 scoped_ptr<ScopedResource> resource(
229 ScopedResource::Create(resource_provider_.get()));
230 resource->Allocate(size, ResourceProvider::TEXTURE_HINT_IMMUTABLE,
231 RGBA_8888);
232 const Resource* const_resource = resource.get();
234 ImageDecodeTask::Vector empty;
235 tasks_.push_back(new TestRasterTaskImpl(
236 const_resource,
237 base::Bind(&TileTaskWorkerPoolTest::OnTaskCompleted,
238 base::Unretained(this), base::Passed(&resource), id),
239 &empty));
242 void AppendTask(unsigned id) { AppendTask(id, gfx::Size(1, 1)); }
244 void AppendBlockingTask(unsigned id, base::Lock* lock) {
245 const gfx::Size size(1, 1);
247 scoped_ptr<ScopedResource> resource(
248 ScopedResource::Create(resource_provider_.get()));
249 resource->Allocate(size, ResourceProvider::TEXTURE_HINT_IMMUTABLE,
250 RGBA_8888);
251 const Resource* const_resource = resource.get();
253 ImageDecodeTask::Vector empty;
254 tasks_.push_back(new BlockingTestRasterTaskImpl(
255 const_resource,
256 base::Bind(&TileTaskWorkerPoolTest::OnTaskCompleted,
257 base::Unretained(this), base::Passed(&resource), id),
258 lock, &empty));
261 const std::vector<RasterTaskResult>& completed_tasks() const {
262 return completed_tasks_;
265 void LoseContext(ContextProvider* context_provider) {
266 if (!context_provider)
267 return;
268 context_provider->ContextGL()->LoseContextCHROMIUM(
269 GL_GUILTY_CONTEXT_RESET_ARB, GL_INNOCENT_CONTEXT_RESET_ARB);
270 context_provider->ContextGL()->Flush();
273 private:
274 void Create3dOutputSurfaceAndResourceProvider() {
275 output_surface_ = FakeOutputSurface::Create3d(context_provider_,
276 worker_context_provider_);
277 CHECK(output_surface_->BindToClient(&output_surface_client_));
278 TestWebGraphicsContext3D* context3d = context_provider_->TestContext3d();
279 context3d->set_support_sync_query(true);
280 resource_provider_ = FakeResourceProvider::Create(
281 output_surface_.get(), nullptr, &gpu_memory_buffer_manager_);
284 void CreateSoftwareOutputSurfaceAndResourceProvider() {
285 output_surface_ = FakeOutputSurface::CreateSoftware(
286 make_scoped_ptr(new SoftwareOutputDevice));
287 CHECK(output_surface_->BindToClient(&output_surface_client_));
288 resource_provider_ = FakeResourceProvider::Create(
289 output_surface_.get(), &shared_bitmap_manager_, nullptr);
292 void OnTaskCompleted(scoped_ptr<ScopedResource> resource,
293 unsigned id,
294 const RasterSource::SolidColorAnalysis& analysis,
295 bool was_canceled) {
296 RasterTaskResult result;
297 result.id = id;
298 result.canceled = was_canceled;
299 completed_tasks_.push_back(result);
302 void OnTimeout() {
303 timed_out_ = true;
304 base::MessageLoop::current()->Quit();
307 protected:
308 scoped_refptr<TestContextProvider> context_provider_;
309 scoped_refptr<TestContextProvider> worker_context_provider_;
310 FakeOutputSurfaceClient output_surface_client_;
311 scoped_ptr<FakeOutputSurface> output_surface_;
312 scoped_ptr<ResourceProvider> resource_provider_;
313 scoped_ptr<TileTaskWorkerPool> tile_task_worker_pool_;
314 TestGpuMemoryBufferManager gpu_memory_buffer_manager_;
315 TestSharedBitmapManager shared_bitmap_manager_;
316 TestTaskGraphRunner task_graph_runner_;
317 base::CancelableClosure timeout_;
318 UniqueNotifier all_tile_tasks_finished_;
319 int timeout_seconds_;
320 bool timed_out_;
321 RasterTaskVector tasks_;
322 std::vector<RasterTaskResult> completed_tasks_;
323 TaskSetCollection completed_task_sets_;
326 TEST_P(TileTaskWorkerPoolTest, Basic) {
327 AppendTask(0u);
328 AppendTask(1u);
329 ScheduleTasks();
331 RunMessageLoopUntilAllTasksHaveCompleted();
333 ASSERT_EQ(2u, completed_tasks().size());
334 EXPECT_FALSE(completed_tasks()[0].canceled);
335 EXPECT_FALSE(completed_tasks()[1].canceled);
338 TEST_P(TileTaskWorkerPoolTest, FailedMapResource) {
339 if (GetParam() == TILE_TASK_WORKER_POOL_TYPE_BITMAP)
340 return;
342 TestWebGraphicsContext3D* context3d = context_provider_->TestContext3d();
343 context3d->set_times_map_buffer_chromium_succeeds(0);
344 AppendTask(0u);
345 ScheduleTasks();
347 RunMessageLoopUntilAllTasksHaveCompleted();
349 ASSERT_EQ(1u, completed_tasks().size());
350 EXPECT_FALSE(completed_tasks()[0].canceled);
353 // This test checks that replacing a pending raster task with another does
354 // not prevent the DidFinishRunningTileTasks notification from being sent.
355 TEST_P(TileTaskWorkerPoolTest, FalseThrottling) {
356 base::Lock lock;
358 // Schedule a task that is prevented from completing with a lock.
359 lock.Acquire();
360 AppendBlockingTask(0u, &lock);
361 ScheduleTasks();
363 // Schedule another task to replace the still-pending task. Because the old
364 // task is not a throttled task in the new task set, it should not prevent
365 // DidFinishRunningTileTasks from getting signaled.
366 RasterTaskVector tasks;
367 tasks.swap(tasks_);
368 AppendTask(1u);
369 ScheduleTasks();
371 // Unblock the first task to allow the second task to complete.
372 lock.Release();
374 RunMessageLoopUntilAllTasksHaveCompleted();
377 TEST_P(TileTaskWorkerPoolTest, LostContext) {
378 LoseContext(output_surface_->context_provider());
379 LoseContext(output_surface_->worker_context_provider());
381 AppendTask(0u);
382 AppendTask(1u);
383 ScheduleTasks();
385 RunMessageLoopUntilAllTasksHaveCompleted();
387 ASSERT_EQ(2u, completed_tasks().size());
388 EXPECT_FALSE(completed_tasks()[0].canceled);
389 EXPECT_FALSE(completed_tasks()[1].canceled);
392 TEST_P(TileTaskWorkerPoolTest, ScheduleEmptyStillTriggersCallback) {
393 // Don't append any tasks, just call ScheduleTasks.
394 ScheduleTasks();
396 EXPECT_FALSE(completed_task_sets_[REQUIRED_FOR_ACTIVATION]);
397 EXPECT_FALSE(completed_task_sets_[REQUIRED_FOR_DRAW]);
398 EXPECT_FALSE(completed_task_sets_[ALL]);
400 RunMessageLoopUntilAllTasksHaveCompleted();
402 EXPECT_TRUE(completed_task_sets_[REQUIRED_FOR_ACTIVATION]);
403 EXPECT_TRUE(completed_task_sets_[REQUIRED_FOR_DRAW]);
404 EXPECT_TRUE(completed_task_sets_[ALL]);
407 INSTANTIATE_TEST_CASE_P(TileTaskWorkerPoolTests,
408 TileTaskWorkerPoolTest,
409 ::testing::Values(TILE_TASK_WORKER_POOL_TYPE_ZERO_COPY,
410 TILE_TASK_WORKER_POOL_TYPE_ONE_COPY,
411 TILE_TASK_WORKER_POOL_TYPE_GPU,
412 TILE_TASK_WORKER_POOL_TYPE_BITMAP));
414 } // namespace
415 } // namespace cc