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/pixel_buffer_tile_task_worker_pool.h"
22 #include "cc/raster/raster_buffer.h"
23 #include "cc/raster/tile_task_runner.h"
24 #include "cc/raster/zero_copy_tile_task_worker_pool.h"
25 #include "cc/resources/resource_pool.h"
26 #include "cc/resources/resource_provider.h"
27 #include "cc/resources/scoped_resource.h"
28 #include "cc/test/fake_output_surface.h"
29 #include "cc/test/fake_output_surface_client.h"
30 #include "cc/test/fake_picture_pile_impl.h"
31 #include "cc/test/fake_resource_provider.h"
32 #include "cc/test/test_gpu_memory_buffer_manager.h"
33 #include "cc/test/test_shared_bitmap_manager.h"
34 #include "cc/test/test_task_graph_runner.h"
35 #include "cc/test/test_web_graphics_context_3d.h"
36 #include "gpu/GLES2/gl2extchromium.h"
37 #include "testing/gtest/include/gtest/gtest.h"
42 const size_t kMaxTransferBufferUsageBytes
= 10000U;
43 const size_t kMaxBytesPerCopyOperation
= 1000U;
44 const size_t kMaxStagingBuffers
= 32U;
46 // A resource of this dimension^2 * 4 must be greater than the above transfer
48 const size_t kLargeResourceDimension
= 1000U;
50 enum TileTaskWorkerPoolType
{
51 TILE_TASK_WORKER_POOL_TYPE_PIXEL_BUFFER
,
52 TILE_TASK_WORKER_POOL_TYPE_ZERO_COPY
,
53 TILE_TASK_WORKER_POOL_TYPE_ONE_COPY
,
54 TILE_TASK_WORKER_POOL_TYPE_GPU
,
55 TILE_TASK_WORKER_POOL_TYPE_BITMAP
58 class TestRasterTaskImpl
: public RasterTask
{
60 typedef base::Callback
<void(const RasterSource::SolidColorAnalysis
& analysis
,
61 bool was_canceled
)> Reply
;
63 TestRasterTaskImpl(const Resource
* resource
,
65 ImageDecodeTask::Vector
* dependencies
)
66 : RasterTask(resource
, dependencies
),
68 picture_pile_(FakePicturePileImpl::CreateEmptyPile(gfx::Size(1, 1),
71 // Overridden from Task:
72 void RunOnWorkerThread() override
{
73 uint64_t new_content_id
= 0;
74 raster_buffer_
->Playback(picture_pile_
.get(), gfx::Rect(1, 1),
75 gfx::Rect(1, 1), new_content_id
, 1.f
, true);
78 // Overridden from TileTask:
79 void ScheduleOnOriginThread(TileTaskClient
* client
) override
{
80 // The raster buffer has no tile ids associated with it for partial update,
81 // so doesn't need to provide a valid dirty rect.
82 raster_buffer_
= client
->AcquireBufferForRaster(resource(), 0, 0);
84 void CompleteOnOriginThread(TileTaskClient
* client
) override
{
85 client
->ReleaseBufferForRaster(raster_buffer_
.Pass());
87 void RunReplyOnOriginThread() override
{
88 reply_
.Run(RasterSource::SolidColorAnalysis(), !HasFinishedRunning());
92 ~TestRasterTaskImpl() override
{}
96 scoped_ptr
<RasterBuffer
> raster_buffer_
;
97 scoped_refptr
<PicturePileImpl
> picture_pile_
;
99 DISALLOW_COPY_AND_ASSIGN(TestRasterTaskImpl
);
102 class BlockingTestRasterTaskImpl
: public TestRasterTaskImpl
{
104 BlockingTestRasterTaskImpl(const Resource
* resource
,
107 ImageDecodeTask::Vector
* dependencies
)
108 : TestRasterTaskImpl(resource
, reply
, dependencies
), lock_(lock
) {}
110 // Overridden from Task:
111 void RunOnWorkerThread() override
{
112 base::AutoLock
lock(*lock_
);
113 TestRasterTaskImpl::RunOnWorkerThread();
116 // Overridden from TileTask:
117 void RunReplyOnOriginThread() override
{}
120 ~BlockingTestRasterTaskImpl() override
{}
125 DISALLOW_COPY_AND_ASSIGN(BlockingTestRasterTaskImpl
);
128 class TileTaskWorkerPoolTest
129 : public testing::TestWithParam
<TileTaskWorkerPoolType
>,
130 public TileTaskRunnerClient
{
132 struct RasterTaskResult
{
137 typedef std::vector
<scoped_refptr
<RasterTask
>> RasterTaskVector
;
139 enum NamedTaskSet
{ REQUIRED_FOR_ACTIVATION
, REQUIRED_FOR_DRAW
, ALL
};
141 TileTaskWorkerPoolTest()
142 : context_provider_(TestContextProvider::Create()),
143 worker_context_provider_(TestContextProvider::Create()),
144 all_tile_tasks_finished_(
145 base::ThreadTaskRunnerHandle::Get().get(),
146 base::Bind(&TileTaskWorkerPoolTest::AllTileTasksFinished
,
147 base::Unretained(this))),
151 // Overridden from testing::Test:
152 void SetUp() override
{
153 switch (GetParam()) {
154 case TILE_TASK_WORKER_POOL_TYPE_PIXEL_BUFFER
:
155 Create3dOutputSurfaceAndResourceProvider();
156 tile_task_worker_pool_
= PixelBufferTileTaskWorkerPool::Create(
157 base::ThreadTaskRunnerHandle::Get().get(), &task_graph_runner_
,
158 context_provider_
.get(), resource_provider_
.get(),
159 kMaxTransferBufferUsageBytes
);
161 case TILE_TASK_WORKER_POOL_TYPE_ZERO_COPY
:
162 Create3dOutputSurfaceAndResourceProvider();
163 tile_task_worker_pool_
= ZeroCopyTileTaskWorkerPool::Create(
164 base::ThreadTaskRunnerHandle::Get().get(), &task_graph_runner_
,
165 resource_provider_
.get());
167 case TILE_TASK_WORKER_POOL_TYPE_ONE_COPY
:
168 Create3dOutputSurfaceAndResourceProvider();
169 tile_task_worker_pool_
= OneCopyTileTaskWorkerPool::Create(
170 base::ThreadTaskRunnerHandle::Get().get(), &task_graph_runner_
,
171 context_provider_
.get(), resource_provider_
.get(),
172 kMaxBytesPerCopyOperation
, false, kMaxStagingBuffers
);
174 case TILE_TASK_WORKER_POOL_TYPE_GPU
:
175 Create3dOutputSurfaceAndResourceProvider();
176 tile_task_worker_pool_
= GpuTileTaskWorkerPool::Create(
177 base::ThreadTaskRunnerHandle::Get().get(), &task_graph_runner_
,
178 context_provider_
.get(), resource_provider_
.get(), false, 0);
180 case TILE_TASK_WORKER_POOL_TYPE_BITMAP
:
181 CreateSoftwareOutputSurfaceAndResourceProvider();
182 tile_task_worker_pool_
= BitmapTileTaskWorkerPool::Create(
183 base::ThreadTaskRunnerHandle::Get().get(), &task_graph_runner_
,
184 resource_provider_
.get());
188 DCHECK(tile_task_worker_pool_
);
189 tile_task_worker_pool_
->AsTileTaskRunner()->SetClient(this);
192 void TearDown() override
{
193 tile_task_worker_pool_
->AsTileTaskRunner()->Shutdown();
194 tile_task_worker_pool_
->AsTileTaskRunner()->CheckForCompletedTasks();
197 void AllTileTasksFinished() {
198 tile_task_worker_pool_
->AsTileTaskRunner()->CheckForCompletedTasks();
199 base::MessageLoop::current()->Quit();
202 // Overriden from TileTaskWorkerPoolClient:
203 void DidFinishRunningTileTasks(TaskSet task_set
) override
{
204 EXPECT_FALSE(completed_task_sets_
[task_set
]);
205 completed_task_sets_
[task_set
] = true;
206 if (task_set
== ALL
) {
207 EXPECT_TRUE((~completed_task_sets_
).none());
208 all_tile_tasks_finished_
.Schedule();
212 TaskSetCollection
TasksThatShouldBeForcedToComplete() const override
{
213 return TaskSetCollection();
216 void RunMessageLoopUntilAllTasksHaveCompleted() {
217 if (timeout_seconds_
) {
218 timeout_
.Reset(base::Bind(&TileTaskWorkerPoolTest::OnTimeout
,
219 base::Unretained(this)));
220 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
221 FROM_HERE
, timeout_
.callback(),
222 base::TimeDelta::FromSeconds(timeout_seconds_
));
225 base::MessageLoop::current()->Run();
229 ASSERT_FALSE(timed_out_
) << "Test timed out";
232 void ScheduleTasks() {
235 for (RasterTaskVector::const_iterator it
= tasks_
.begin();
236 it
!= tasks_
.end(); ++it
) {
237 TaskSetCollection task_sets
;
238 task_sets
[REQUIRED_FOR_ACTIVATION
] = true;
239 task_sets
[REQUIRED_FOR_DRAW
] = true;
240 task_sets
[ALL
] = true;
241 queue
.items
.push_back(TileTaskQueue::Item(it
->get(), task_sets
));
244 completed_task_sets_
.reset();
245 tile_task_worker_pool_
->AsTileTaskRunner()->ScheduleTasks(&queue
);
248 void AppendTask(unsigned id
, const gfx::Size
& size
) {
249 scoped_ptr
<ScopedResource
> resource(
250 ScopedResource::Create(resource_provider_
.get()));
251 resource
->Allocate(size
, ResourceProvider::TEXTURE_HINT_IMMUTABLE
,
253 const Resource
* const_resource
= resource
.get();
255 ImageDecodeTask::Vector empty
;
256 tasks_
.push_back(new TestRasterTaskImpl(
258 base::Bind(&TileTaskWorkerPoolTest::OnTaskCompleted
,
259 base::Unretained(this), base::Passed(&resource
), id
),
263 void AppendTask(unsigned id
) { AppendTask(id
, gfx::Size(1, 1)); }
265 void AppendBlockingTask(unsigned id
, base::Lock
* lock
) {
266 const gfx::Size
size(1, 1);
268 scoped_ptr
<ScopedResource
> resource(
269 ScopedResource::Create(resource_provider_
.get()));
270 resource
->Allocate(size
, ResourceProvider::TEXTURE_HINT_IMMUTABLE
,
272 const Resource
* const_resource
= resource
.get();
274 ImageDecodeTask::Vector empty
;
275 tasks_
.push_back(new BlockingTestRasterTaskImpl(
277 base::Bind(&TileTaskWorkerPoolTest::OnTaskCompleted
,
278 base::Unretained(this), base::Passed(&resource
), id
),
282 const std::vector
<RasterTaskResult
>& completed_tasks() const {
283 return completed_tasks_
;
286 void LoseContext(ContextProvider
* context_provider
) {
287 if (!context_provider
)
289 context_provider
->ContextGL()->LoseContextCHROMIUM(
290 GL_GUILTY_CONTEXT_RESET_ARB
, GL_INNOCENT_CONTEXT_RESET_ARB
);
291 context_provider
->ContextGL()->Flush();
295 void Create3dOutputSurfaceAndResourceProvider() {
296 output_surface_
= FakeOutputSurface::Create3d(context_provider_
,
297 worker_context_provider_
);
298 CHECK(output_surface_
->BindToClient(&output_surface_client_
));
299 TestWebGraphicsContext3D
* context3d
= context_provider_
->TestContext3d();
300 context3d
->set_support_sync_query(true);
301 resource_provider_
= FakeResourceProvider::Create(
302 output_surface_
.get(), nullptr, &gpu_memory_buffer_manager_
);
305 void CreateSoftwareOutputSurfaceAndResourceProvider() {
306 output_surface_
= FakeOutputSurface::CreateSoftware(
307 make_scoped_ptr(new SoftwareOutputDevice
));
308 CHECK(output_surface_
->BindToClient(&output_surface_client_
));
309 resource_provider_
= FakeResourceProvider::Create(
310 output_surface_
.get(), &shared_bitmap_manager_
, nullptr);
313 void OnTaskCompleted(scoped_ptr
<ScopedResource
> resource
,
315 const RasterSource::SolidColorAnalysis
& analysis
,
317 RasterTaskResult result
;
319 result
.canceled
= was_canceled
;
320 completed_tasks_
.push_back(result
);
325 base::MessageLoop::current()->Quit();
329 scoped_refptr
<TestContextProvider
> context_provider_
;
330 scoped_refptr
<TestContextProvider
> worker_context_provider_
;
331 FakeOutputSurfaceClient output_surface_client_
;
332 scoped_ptr
<FakeOutputSurface
> output_surface_
;
333 scoped_ptr
<ResourceProvider
> resource_provider_
;
334 scoped_ptr
<TileTaskWorkerPool
> tile_task_worker_pool_
;
335 TestGpuMemoryBufferManager gpu_memory_buffer_manager_
;
336 TestSharedBitmapManager shared_bitmap_manager_
;
337 TestTaskGraphRunner task_graph_runner_
;
338 base::CancelableClosure timeout_
;
339 UniqueNotifier all_tile_tasks_finished_
;
340 int timeout_seconds_
;
342 RasterTaskVector tasks_
;
343 std::vector
<RasterTaskResult
> completed_tasks_
;
344 TaskSetCollection completed_task_sets_
;
347 TEST_P(TileTaskWorkerPoolTest
, Basic
) {
352 RunMessageLoopUntilAllTasksHaveCompleted();
354 ASSERT_EQ(2u, completed_tasks().size());
355 EXPECT_FALSE(completed_tasks()[0].canceled
);
356 EXPECT_FALSE(completed_tasks()[1].canceled
);
359 TEST_P(TileTaskWorkerPoolTest
, FailedMapResource
) {
360 if (GetParam() == TILE_TASK_WORKER_POOL_TYPE_BITMAP
)
363 TestWebGraphicsContext3D
* context3d
= context_provider_
->TestContext3d();
364 context3d
->set_times_map_buffer_chromium_succeeds(0);
368 RunMessageLoopUntilAllTasksHaveCompleted();
370 ASSERT_EQ(1u, completed_tasks().size());
371 EXPECT_FALSE(completed_tasks()[0].canceled
);
374 // This test checks that replacing a pending raster task with another does
375 // not prevent the DidFinishRunningTileTasks notification from being sent.
376 TEST_P(TileTaskWorkerPoolTest
, FalseThrottling
) {
379 // Schedule a task that is prevented from completing with a lock.
381 AppendBlockingTask(0u, &lock
);
384 // Schedule another task to replace the still-pending task. Because the old
385 // task is not a throttled task in the new task set, it should not prevent
386 // DidFinishRunningTileTasks from getting signaled.
387 RasterTaskVector tasks
;
392 // Unblock the first task to allow the second task to complete.
395 RunMessageLoopUntilAllTasksHaveCompleted();
398 TEST_P(TileTaskWorkerPoolTest
, LargeResources
) {
399 gfx::Size
size(kLargeResourceDimension
, kLargeResourceDimension
);
402 // Verify a resource of this size is larger than the transfer buffer.
403 scoped_ptr
<ScopedResource
> resource(
404 ScopedResource::Create(resource_provider_
.get()));
405 resource
->Allocate(size
, ResourceProvider::TEXTURE_HINT_IMMUTABLE
,
407 EXPECT_GE(ResourceUtil::UncheckedSizeInBytes
<size_t>(resource
->size(),
409 kMaxTransferBufferUsageBytes
);
412 AppendTask(0u, size
);
413 AppendTask(1u, size
);
414 AppendTask(2u, size
);
417 // This will time out if a resource that is larger than the throttle limit
418 // never gets scheduled.
419 RunMessageLoopUntilAllTasksHaveCompleted();
422 TEST_P(TileTaskWorkerPoolTest
, LostContext
) {
423 LoseContext(output_surface_
->context_provider());
424 LoseContext(output_surface_
->worker_context_provider());
430 RunMessageLoopUntilAllTasksHaveCompleted();
432 ASSERT_EQ(2u, completed_tasks().size());
433 EXPECT_FALSE(completed_tasks()[0].canceled
);
434 EXPECT_FALSE(completed_tasks()[1].canceled
);
437 TEST_P(TileTaskWorkerPoolTest
, ScheduleEmptyStillTriggersCallback
) {
438 // Don't append any tasks, just call ScheduleTasks.
441 EXPECT_FALSE(completed_task_sets_
[REQUIRED_FOR_ACTIVATION
]);
442 EXPECT_FALSE(completed_task_sets_
[REQUIRED_FOR_DRAW
]);
443 EXPECT_FALSE(completed_task_sets_
[ALL
]);
445 RunMessageLoopUntilAllTasksHaveCompleted();
447 EXPECT_TRUE(completed_task_sets_
[REQUIRED_FOR_ACTIVATION
]);
448 EXPECT_TRUE(completed_task_sets_
[REQUIRED_FOR_DRAW
]);
449 EXPECT_TRUE(completed_task_sets_
[ALL
]);
452 INSTANTIATE_TEST_CASE_P(
453 TileTaskWorkerPoolTests
,
454 TileTaskWorkerPoolTest
,
455 ::testing::Values(TILE_TASK_WORKER_POOL_TYPE_PIXEL_BUFFER
,
456 TILE_TASK_WORKER_POOL_TYPE_ZERO_COPY
,
457 TILE_TASK_WORKER_POOL_TYPE_ONE_COPY
,
458 TILE_TASK_WORKER_POOL_TYPE_GPU
,
459 TILE_TASK_WORKER_POOL_TYPE_BITMAP
));