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/resources/tile_task_worker_pool.h"
10 #include "base/cancelable_callback.h"
11 #include "cc/base/unique_notifier.h"
12 #include "cc/resources/bitmap_tile_task_worker_pool.h"
13 #include "cc/resources/gpu_tile_task_worker_pool.h"
14 #include "cc/resources/one_copy_tile_task_worker_pool.h"
15 #include "cc/resources/picture_pile.h"
16 #include "cc/resources/picture_pile_impl.h"
17 #include "cc/resources/pixel_buffer_tile_task_worker_pool.h"
18 #include "cc/resources/raster_buffer.h"
19 #include "cc/resources/resource_pool.h"
20 #include "cc/resources/resource_provider.h"
21 #include "cc/resources/scoped_resource.h"
22 #include "cc/resources/tile_task_runner.h"
23 #include "cc/resources/zero_copy_tile_task_worker_pool.h"
24 #include "cc/test/fake_output_surface.h"
25 #include "cc/test/fake_output_surface_client.h"
26 #include "cc/test/fake_picture_pile_impl.h"
27 #include "cc/test/test_gpu_memory_buffer_manager.h"
28 #include "cc/test/test_shared_bitmap_manager.h"
29 #include "cc/test/test_web_graphics_context_3d.h"
30 #include "testing/gtest/include/gtest/gtest.h"
35 const size_t kMaxTransferBufferUsageBytes
= 10000U;
36 // A resource of this dimension^2 * 4 must be greater than the above transfer
38 const size_t kLargeResourceDimension
= 1000U;
40 enum TileTaskWorkerPoolType
{
41 TILE_TASK_WORKER_POOL_TYPE_PIXEL_BUFFER
,
42 TILE_TASK_WORKER_POOL_TYPE_ZERO_COPY
,
43 TILE_TASK_WORKER_POOL_TYPE_ONE_COPY
,
44 TILE_TASK_WORKER_POOL_TYPE_GPU
,
45 TILE_TASK_WORKER_POOL_TYPE_BITMAP
48 class TestRasterTaskImpl
: public RasterTask
{
50 typedef base::Callback
<void(const RasterSource::SolidColorAnalysis
& analysis
,
51 bool was_canceled
)> Reply
;
53 TestRasterTaskImpl(const Resource
* resource
,
55 ImageDecodeTask::Vector
* dependencies
)
56 : RasterTask(resource
, dependencies
),
58 picture_pile_(FakePicturePileImpl::CreateEmptyPile(gfx::Size(1, 1),
61 // Overridden from Task:
62 void RunOnWorkerThread() override
{
63 raster_buffer_
->Playback(picture_pile_
.get(), gfx::Rect(0, 0, 1, 1), 1.0);
66 // Overridden from TileTask:
67 void ScheduleOnOriginThread(TileTaskClient
* client
) override
{
68 raster_buffer_
= client
->AcquireBufferForRaster(resource());
70 void CompleteOnOriginThread(TileTaskClient
* client
) override
{
71 client
->ReleaseBufferForRaster(raster_buffer_
.Pass());
73 void RunReplyOnOriginThread() override
{
74 reply_
.Run(RasterSource::SolidColorAnalysis(), !HasFinishedRunning());
78 ~TestRasterTaskImpl() override
{}
82 scoped_ptr
<RasterBuffer
> raster_buffer_
;
83 scoped_refptr
<PicturePileImpl
> picture_pile_
;
85 DISALLOW_COPY_AND_ASSIGN(TestRasterTaskImpl
);
88 class BlockingTestRasterTaskImpl
: public TestRasterTaskImpl
{
90 BlockingTestRasterTaskImpl(const Resource
* resource
,
93 ImageDecodeTask::Vector
* dependencies
)
94 : TestRasterTaskImpl(resource
, reply
, dependencies
), lock_(lock
) {}
96 // Overridden from Task:
97 void RunOnWorkerThread() override
{
98 base::AutoLock
lock(*lock_
);
99 TestRasterTaskImpl::RunOnWorkerThread();
102 // Overridden from TileTask:
103 void RunReplyOnOriginThread() override
{}
106 ~BlockingTestRasterTaskImpl() override
{}
111 DISALLOW_COPY_AND_ASSIGN(BlockingTestRasterTaskImpl
);
114 class TileTaskWorkerPoolTest
115 : public testing::TestWithParam
<TileTaskWorkerPoolType
>,
116 public TileTaskRunnerClient
{
118 struct RasterTaskResult
{
123 typedef std::vector
<scoped_refptr
<RasterTask
>> RasterTaskVector
;
125 enum NamedTaskSet
{ REQUIRED_FOR_ACTIVATION
, REQUIRED_FOR_DRAW
, ALL
};
127 TileTaskWorkerPoolTest()
128 : context_provider_(TestContextProvider::Create()),
129 all_tile_tasks_finished_(
130 base::MessageLoopProxy::current().get(),
131 base::Bind(&TileTaskWorkerPoolTest::AllTileTasksFinished
,
132 base::Unretained(this))),
136 // Overridden from testing::Test:
137 void SetUp() override
{
138 switch (GetParam()) {
139 case TILE_TASK_WORKER_POOL_TYPE_PIXEL_BUFFER
:
140 Create3dOutputSurfaceAndResourceProvider();
141 tile_task_worker_pool_
= PixelBufferTileTaskWorkerPool::Create(
142 base::MessageLoopProxy::current().get(),
143 TileTaskWorkerPool::GetTaskGraphRunner(), context_provider_
.get(),
144 resource_provider_
.get(), kMaxTransferBufferUsageBytes
);
146 case TILE_TASK_WORKER_POOL_TYPE_ZERO_COPY
:
147 Create3dOutputSurfaceAndResourceProvider();
148 tile_task_worker_pool_
= ZeroCopyTileTaskWorkerPool::Create(
149 base::MessageLoopProxy::current().get(),
150 TileTaskWorkerPool::GetTaskGraphRunner(), resource_provider_
.get());
152 case TILE_TASK_WORKER_POOL_TYPE_ONE_COPY
:
153 Create3dOutputSurfaceAndResourceProvider();
154 staging_resource_pool_
= ResourcePool::Create(resource_provider_
.get(),
156 tile_task_worker_pool_
= OneCopyTileTaskWorkerPool::Create(
157 base::MessageLoopProxy::current().get(),
158 TileTaskWorkerPool::GetTaskGraphRunner(), context_provider_
.get(),
159 resource_provider_
.get(), staging_resource_pool_
.get());
161 case TILE_TASK_WORKER_POOL_TYPE_GPU
:
162 Create3dOutputSurfaceAndResourceProvider();
163 tile_task_worker_pool_
= GpuTileTaskWorkerPool::Create(
164 base::MessageLoopProxy::current().get(),
165 TileTaskWorkerPool::GetTaskGraphRunner(),
166 resource_provider_
.get());
168 case TILE_TASK_WORKER_POOL_TYPE_BITMAP
:
169 CreateSoftwareOutputSurfaceAndResourceProvider();
170 tile_task_worker_pool_
= BitmapTileTaskWorkerPool::Create(
171 base::MessageLoopProxy::current().get(),
172 TileTaskWorkerPool::GetTaskGraphRunner(), resource_provider_
.get());
176 DCHECK(tile_task_worker_pool_
);
177 tile_task_worker_pool_
->AsTileTaskRunner()->SetClient(this);
180 void TearDown() override
{
181 tile_task_worker_pool_
->AsTileTaskRunner()->Shutdown();
182 tile_task_worker_pool_
->AsTileTaskRunner()->CheckForCompletedTasks();
185 void AllTileTasksFinished() {
186 tile_task_worker_pool_
->AsTileTaskRunner()->CheckForCompletedTasks();
187 base::MessageLoop::current()->Quit();
190 // Overriden from TileTaskWorkerPoolClient:
191 void DidFinishRunningTileTasks(TaskSet task_set
) override
{
192 EXPECT_FALSE(completed_task_sets_
[task_set
]);
193 completed_task_sets_
[task_set
] = true;
194 if (task_set
== ALL
) {
195 EXPECT_TRUE((~completed_task_sets_
).none());
196 all_tile_tasks_finished_
.Schedule();
200 TaskSetCollection
TasksThatShouldBeForcedToComplete() const override
{
201 return TaskSetCollection();
204 void RunMessageLoopUntilAllTasksHaveCompleted() {
205 if (timeout_seconds_
) {
206 timeout_
.Reset(base::Bind(&TileTaskWorkerPoolTest::OnTimeout
,
207 base::Unretained(this)));
208 base::MessageLoopProxy::current()->PostDelayedTask(
209 FROM_HERE
, timeout_
.callback(),
210 base::TimeDelta::FromSeconds(timeout_seconds_
));
213 base::MessageLoop::current()->Run();
217 ASSERT_FALSE(timed_out_
) << "Test timed out";
220 void ScheduleTasks() {
223 for (RasterTaskVector::const_iterator it
= tasks_
.begin();
224 it
!= tasks_
.end(); ++it
) {
225 TaskSetCollection task_sets
;
226 task_sets
[REQUIRED_FOR_ACTIVATION
] = true;
227 task_sets
[REQUIRED_FOR_DRAW
] = true;
228 task_sets
[ALL
] = true;
229 queue
.items
.push_back(TileTaskQueue::Item(it
->get(), task_sets
));
232 completed_task_sets_
.reset();
233 tile_task_worker_pool_
->AsTileTaskRunner()->ScheduleTasks(&queue
);
236 void AppendTask(unsigned id
, const gfx::Size
& size
) {
237 scoped_ptr
<ScopedResource
> resource(
238 ScopedResource::Create(resource_provider_
.get()));
239 resource
->Allocate(size
, ResourceProvider::TextureHintImmutable
, RGBA_8888
);
240 const Resource
* const_resource
= resource
.get();
242 ImageDecodeTask::Vector empty
;
243 tasks_
.push_back(new TestRasterTaskImpl(
245 base::Bind(&TileTaskWorkerPoolTest::OnTaskCompleted
,
246 base::Unretained(this), base::Passed(&resource
), id
),
250 void AppendTask(unsigned id
) { AppendTask(id
, gfx::Size(1, 1)); }
252 void AppendBlockingTask(unsigned id
, base::Lock
* lock
) {
253 const gfx::Size
size(1, 1);
255 scoped_ptr
<ScopedResource
> resource(
256 ScopedResource::Create(resource_provider_
.get()));
257 resource
->Allocate(size
, ResourceProvider::TextureHintImmutable
, RGBA_8888
);
258 const Resource
* const_resource
= resource
.get();
260 ImageDecodeTask::Vector empty
;
261 tasks_
.push_back(new BlockingTestRasterTaskImpl(
263 base::Bind(&TileTaskWorkerPoolTest::OnTaskCompleted
,
264 base::Unretained(this), base::Passed(&resource
), id
),
268 const std::vector
<RasterTaskResult
>& completed_tasks() const {
269 return completed_tasks_
;
273 void Create3dOutputSurfaceAndResourceProvider() {
274 output_surface_
= FakeOutputSurface::Create3d(context_provider_
).Pass();
275 CHECK(output_surface_
->BindToClient(&output_surface_client_
));
276 TestWebGraphicsContext3D
* context3d
= context_provider_
->TestContext3d();
277 context3d
->set_support_sync_query(true);
278 resource_provider_
= ResourceProvider::Create(output_surface_
.get(), NULL
,
279 &gpu_memory_buffer_manager_
,
280 NULL
, 0, false, 1).Pass();
283 void CreateSoftwareOutputSurfaceAndResourceProvider() {
284 output_surface_
= FakeOutputSurface::CreateSoftware(
285 make_scoped_ptr(new SoftwareOutputDevice
));
286 CHECK(output_surface_
->BindToClient(&output_surface_client_
));
288 ResourceProvider::Create(output_surface_
.get(), &shared_bitmap_manager_
,
289 NULL
, NULL
, 0, false, 1).Pass();
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 FakeOutputSurfaceClient output_surface_client_
;
310 scoped_ptr
<FakeOutputSurface
> output_surface_
;
311 scoped_ptr
<ResourceProvider
> resource_provider_
;
312 scoped_ptr
<ResourcePool
> staging_resource_pool_
;
313 scoped_ptr
<TileTaskWorkerPool
> tile_task_worker_pool_
;
314 TestGpuMemoryBufferManager gpu_memory_buffer_manager_
;
315 TestSharedBitmapManager shared_bitmap_manager_
;
316 base::CancelableClosure timeout_
;
317 UniqueNotifier all_tile_tasks_finished_
;
318 int timeout_seconds_
;
320 RasterTaskVector tasks_
;
321 std::vector
<RasterTaskResult
> completed_tasks_
;
322 TaskSetCollection completed_task_sets_
;
325 TEST_P(TileTaskWorkerPoolTest
, Basic
) {
330 RunMessageLoopUntilAllTasksHaveCompleted();
332 ASSERT_EQ(2u, completed_tasks().size());
333 EXPECT_FALSE(completed_tasks()[0].canceled
);
334 EXPECT_FALSE(completed_tasks()[1].canceled
);
337 TEST_P(TileTaskWorkerPoolTest
, FailedMapResource
) {
338 if (GetParam() == TILE_TASK_WORKER_POOL_TYPE_BITMAP
)
341 TestWebGraphicsContext3D
* context3d
= context_provider_
->TestContext3d();
342 context3d
->set_times_map_buffer_chromium_succeeds(0);
346 RunMessageLoopUntilAllTasksHaveCompleted();
348 ASSERT_EQ(1u, completed_tasks().size());
349 EXPECT_FALSE(completed_tasks()[0].canceled
);
352 // This test checks that replacing a pending raster task with another does
353 // not prevent the DidFinishRunningTileTasks notification from being sent.
354 TEST_P(TileTaskWorkerPoolTest
, FalseThrottling
) {
357 // Schedule a task that is prevented from completing with a lock.
359 AppendBlockingTask(0u, &lock
);
362 // Schedule another task to replace the still-pending task. Because the old
363 // task is not a throttled task in the new task set, it should not prevent
364 // DidFinishRunningTileTasks from getting signaled.
365 RasterTaskVector tasks
;
370 // Unblock the first task to allow the second task to complete.
373 RunMessageLoopUntilAllTasksHaveCompleted();
376 TEST_P(TileTaskWorkerPoolTest
, LargeResources
) {
377 gfx::Size
size(kLargeResourceDimension
, kLargeResourceDimension
);
380 // Verify a resource of this size is larger than the transfer buffer.
381 scoped_ptr
<ScopedResource
> resource(
382 ScopedResource::Create(resource_provider_
.get()));
383 resource
->Allocate(size
, ResourceProvider::TextureHintImmutable
, RGBA_8888
);
384 EXPECT_GE(resource
->bytes(), kMaxTransferBufferUsageBytes
);
387 AppendTask(0u, size
);
388 AppendTask(1u, size
);
389 AppendTask(2u, size
);
392 // This will time out if a resource that is larger than the throttle limit
393 // never gets scheduled.
394 RunMessageLoopUntilAllTasksHaveCompleted();
397 INSTANTIATE_TEST_CASE_P(
398 TileTaskWorkerPoolTests
,
399 TileTaskWorkerPoolTest
,
400 ::testing::Values(TILE_TASK_WORKER_POOL_TYPE_PIXEL_BUFFER
,
401 TILE_TASK_WORKER_POOL_TYPE_ZERO_COPY
,
402 TILE_TASK_WORKER_POOL_TYPE_ONE_COPY
,
403 TILE_TASK_WORKER_POOL_TYPE_GPU
,
404 TILE_TASK_WORKER_POOL_TYPE_BITMAP
));