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"
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"
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
{
53 typedef base::Callback
<void(const RasterSource::SolidColorAnalysis
& analysis
,
54 bool was_canceled
)> Reply
;
56 TestRasterTaskImpl(const Resource
* resource
,
58 ImageDecodeTask::Vector
* dependencies
)
59 : RasterTask(dependencies
),
62 picture_pile_(FakePicturePileImpl::CreateEmptyPile(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());
84 ~TestRasterTaskImpl() override
{}
87 const Resource
* resource_
;
89 scoped_ptr
<RasterBuffer
> raster_buffer_
;
90 scoped_refptr
<PicturePileImpl
> picture_pile_
;
92 DISALLOW_COPY_AND_ASSIGN(TestRasterTaskImpl
);
95 class BlockingTestRasterTaskImpl
: public TestRasterTaskImpl
{
97 BlockingTestRasterTaskImpl(const Resource
* resource
,
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();
110 ~BlockingTestRasterTaskImpl() override
{}
115 DISALLOW_COPY_AND_ASSIGN(BlockingTestRasterTaskImpl
);
118 class TileTaskWorkerPoolTest
119 : public testing::TestWithParam
<TileTaskWorkerPoolType
>,
120 public TileTaskRunnerClient
{
122 struct RasterTaskResult
{
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))),
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());
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
);
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);
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());
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();
208 ASSERT_FALSE(timed_out_
) << "Test timed out";
211 void ScheduleTasks() {
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
,
232 const Resource
* const_resource
= resource
.get();
234 ImageDecodeTask::Vector empty
;
235 tasks_
.push_back(new TestRasterTaskImpl(
237 base::Bind(&TileTaskWorkerPoolTest::OnTaskCompleted
,
238 base::Unretained(this), base::Passed(&resource
), id
),
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
,
251 const Resource
* const_resource
= resource
.get();
253 ImageDecodeTask::Vector empty
;
254 tasks_
.push_back(new BlockingTestRasterTaskImpl(
256 base::Bind(&TileTaskWorkerPoolTest::OnTaskCompleted
,
257 base::Unretained(this), base::Passed(&resource
), id
),
261 const std::vector
<RasterTaskResult
>& completed_tasks() const {
262 return completed_tasks_
;
265 void LoseContext(ContextProvider
* context_provider
) {
266 if (!context_provider
)
268 context_provider
->ContextGL()->LoseContextCHROMIUM(
269 GL_GUILTY_CONTEXT_RESET_ARB
, GL_INNOCENT_CONTEXT_RESET_ARB
);
270 context_provider
->ContextGL()->Flush();
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
,
294 const RasterSource::SolidColorAnalysis
& analysis
,
296 RasterTaskResult result
;
298 result
.canceled
= was_canceled
;
299 completed_tasks_
.push_back(result
);
304 base::MessageLoop::current()->Quit();
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_
;
321 RasterTaskVector tasks_
;
322 std::vector
<RasterTaskResult
> completed_tasks_
;
323 TaskSetCollection completed_task_sets_
;
326 TEST_P(TileTaskWorkerPoolTest
, Basic
) {
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
)
342 TestWebGraphicsContext3D
* context3d
= context_provider_
->TestContext3d();
343 context3d
->set_times_map_buffer_chromium_succeeds(0);
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
) {
358 // Schedule a task that is prevented from completing with a lock.
360 AppendBlockingTask(0u, &lock
);
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
;
371 // Unblock the first task to allow the second task to complete.
374 RunMessageLoopUntilAllTasksHaveCompleted();
377 TEST_P(TileTaskWorkerPoolTest
, LostContext
) {
378 LoseContext(output_surface_
->context_provider());
379 LoseContext(output_surface_
->worker_context_provider());
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.
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
));