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_rasterizer.h"
14 #include "cc/resources/gpu_tile_task_worker_pool.h"
15 #include "cc/resources/one_copy_tile_task_worker_pool.h"
16 #include "cc/resources/picture_pile.h"
17 #include "cc/resources/picture_pile_impl.h"
18 #include "cc/resources/pixel_buffer_tile_task_worker_pool.h"
19 #include "cc/resources/raster_buffer.h"
20 #include "cc/resources/resource_pool.h"
21 #include "cc/resources/resource_provider.h"
22 #include "cc/resources/scoped_resource.h"
23 #include "cc/resources/tile_task_runner.h"
24 #include "cc/resources/zero_copy_tile_task_worker_pool.h"
25 #include "cc/test/fake_output_surface.h"
26 #include "cc/test/fake_output_surface_client.h"
27 #include "cc/test/fake_picture_pile_impl.h"
28 #include "cc/test/test_gpu_memory_buffer_manager.h"
29 #include "cc/test/test_shared_bitmap_manager.h"
30 #include "cc/test/test_web_graphics_context_3d.h"
31 #include "testing/gtest/include/gtest/gtest.h"
36 const size_t kMaxTransferBufferUsageBytes
= 10000U;
37 // A resource of this dimension^2 * 4 must be greater than the above transfer
39 const size_t kLargeResourceDimension
= 1000U;
41 enum TileTaskWorkerPoolType
{
42 TILE_TASK_WORKER_POOL_TYPE_PIXEL_BUFFER
,
43 TILE_TASK_WORKER_POOL_TYPE_ZERO_COPY
,
44 TILE_TASK_WORKER_POOL_TYPE_ONE_COPY
,
45 TILE_TASK_WORKER_POOL_TYPE_GPU
,
46 TILE_TASK_WORKER_POOL_TYPE_BITMAP
49 class TestRasterTaskImpl
: public RasterTask
{
51 typedef base::Callback
<void(const RasterSource::SolidColorAnalysis
& analysis
,
52 bool was_canceled
)> Reply
;
54 TestRasterTaskImpl(const Resource
* resource
,
56 ImageDecodeTask::Vector
* dependencies
)
57 : RasterTask(resource
, dependencies
),
59 picture_pile_(FakePicturePileImpl::CreateEmptyPile(gfx::Size(1, 1),
62 // Overridden from Task:
63 void RunOnWorkerThread() override
{
64 raster_buffer_
->Playback(picture_pile_
.get(), gfx::Rect(0, 0, 1, 1), 1.0);
67 // Overridden from TileTask:
68 void ScheduleOnOriginThread(TileTaskClient
* client
) override
{
69 raster_buffer_
= client
->AcquireBufferForRaster(resource());
71 void CompleteOnOriginThread(TileTaskClient
* client
) override
{
72 client
->ReleaseBufferForRaster(raster_buffer_
.Pass());
74 void RunReplyOnOriginThread() override
{
75 reply_
.Run(RasterSource::SolidColorAnalysis(), !HasFinishedRunning());
79 ~TestRasterTaskImpl() override
{}
83 scoped_ptr
<RasterBuffer
> raster_buffer_
;
84 scoped_refptr
<PicturePileImpl
> picture_pile_
;
86 DISALLOW_COPY_AND_ASSIGN(TestRasterTaskImpl
);
89 class BlockingTestRasterTaskImpl
: public TestRasterTaskImpl
{
91 BlockingTestRasterTaskImpl(const Resource
* resource
,
94 ImageDecodeTask::Vector
* dependencies
)
95 : TestRasterTaskImpl(resource
, reply
, dependencies
), lock_(lock
) {}
97 // Overridden from Task:
98 void RunOnWorkerThread() override
{
99 base::AutoLock
lock(*lock_
);
100 TestRasterTaskImpl::RunOnWorkerThread();
103 // Overridden from TileTask:
104 void RunReplyOnOriginThread() override
{}
107 ~BlockingTestRasterTaskImpl() override
{}
112 DISALLOW_COPY_AND_ASSIGN(BlockingTestRasterTaskImpl
);
115 class TileTaskWorkerPoolTest
116 : public testing::TestWithParam
<TileTaskWorkerPoolType
>,
117 public TileTaskRunnerClient
{
119 struct RasterTaskResult
{
124 typedef std::vector
<scoped_refptr
<RasterTask
>> RasterTaskVector
;
126 enum NamedTaskSet
{ REQUIRED_FOR_ACTIVATION
, REQUIRED_FOR_DRAW
, ALL
};
128 TileTaskWorkerPoolTest()
129 : context_provider_(TestContextProvider::Create()),
130 worker_context_provider_(TestContextProvider::Create()),
131 all_tile_tasks_finished_(
132 base::MessageLoopProxy::current().get(),
133 base::Bind(&TileTaskWorkerPoolTest::AllTileTasksFinished
,
134 base::Unretained(this))),
138 // Overridden from testing::Test:
139 void SetUp() override
{
140 switch (GetParam()) {
141 case TILE_TASK_WORKER_POOL_TYPE_PIXEL_BUFFER
:
142 Create3dOutputSurfaceAndResourceProvider();
143 tile_task_worker_pool_
= PixelBufferTileTaskWorkerPool::Create(
144 base::MessageLoopProxy::current().get(),
145 TileTaskWorkerPool::GetTaskGraphRunner(), context_provider_
.get(),
146 resource_provider_
.get(), kMaxTransferBufferUsageBytes
);
148 case TILE_TASK_WORKER_POOL_TYPE_ZERO_COPY
:
149 Create3dOutputSurfaceAndResourceProvider();
150 tile_task_worker_pool_
= ZeroCopyTileTaskWorkerPool::Create(
151 base::MessageLoopProxy::current().get(),
152 TileTaskWorkerPool::GetTaskGraphRunner(), resource_provider_
.get());
154 case TILE_TASK_WORKER_POOL_TYPE_ONE_COPY
:
155 Create3dOutputSurfaceAndResourceProvider();
156 staging_resource_pool_
= ResourcePool::Create(resource_provider_
.get(),
158 tile_task_worker_pool_
= OneCopyTileTaskWorkerPool::Create(
159 base::MessageLoopProxy::current().get(),
160 TileTaskWorkerPool::GetTaskGraphRunner(), context_provider_
.get(),
161 resource_provider_
.get(), staging_resource_pool_
.get());
163 case TILE_TASK_WORKER_POOL_TYPE_GPU
:
164 Create3dOutputSurfaceAndResourceProvider();
165 rasterizer_
= GpuRasterizer::Create(
166 context_provider_
.get(), resource_provider_
.get(), false, false, 0);
167 tile_task_worker_pool_
= GpuTileTaskWorkerPool::Create(
168 base::MessageLoopProxy::current().get(),
169 TileTaskWorkerPool::GetTaskGraphRunner(),
170 static_cast<GpuRasterizer
*>(rasterizer_
.get()));
172 case TILE_TASK_WORKER_POOL_TYPE_BITMAP
:
173 CreateSoftwareOutputSurfaceAndResourceProvider();
174 tile_task_worker_pool_
= BitmapTileTaskWorkerPool::Create(
175 base::MessageLoopProxy::current().get(),
176 TileTaskWorkerPool::GetTaskGraphRunner(), resource_provider_
.get());
180 DCHECK(tile_task_worker_pool_
);
181 tile_task_worker_pool_
->AsTileTaskRunner()->SetClient(this);
184 void TearDown() override
{
185 tile_task_worker_pool_
->AsTileTaskRunner()->Shutdown();
186 tile_task_worker_pool_
->AsTileTaskRunner()->CheckForCompletedTasks();
189 void AllTileTasksFinished() {
190 tile_task_worker_pool_
->AsTileTaskRunner()->CheckForCompletedTasks();
191 base::MessageLoop::current()->Quit();
194 // Overriden from TileTaskWorkerPoolClient:
195 void DidFinishRunningTileTasks(TaskSet task_set
) override
{
196 EXPECT_FALSE(completed_task_sets_
[task_set
]);
197 completed_task_sets_
[task_set
] = true;
198 if (task_set
== ALL
) {
199 EXPECT_TRUE((~completed_task_sets_
).none());
200 all_tile_tasks_finished_
.Schedule();
204 TaskSetCollection
TasksThatShouldBeForcedToComplete() const override
{
205 return TaskSetCollection();
208 void RunMessageLoopUntilAllTasksHaveCompleted() {
209 if (timeout_seconds_
) {
210 timeout_
.Reset(base::Bind(&TileTaskWorkerPoolTest::OnTimeout
,
211 base::Unretained(this)));
212 base::MessageLoopProxy::current()->PostDelayedTask(
213 FROM_HERE
, timeout_
.callback(),
214 base::TimeDelta::FromSeconds(timeout_seconds_
));
217 base::MessageLoop::current()->Run();
221 ASSERT_FALSE(timed_out_
) << "Test timed out";
224 void ScheduleTasks() {
227 for (RasterTaskVector::const_iterator it
= tasks_
.begin();
228 it
!= tasks_
.end(); ++it
) {
229 TaskSetCollection task_sets
;
230 task_sets
[REQUIRED_FOR_ACTIVATION
] = true;
231 task_sets
[REQUIRED_FOR_DRAW
] = true;
232 task_sets
[ALL
] = true;
233 queue
.items
.push_back(TileTaskQueue::Item(it
->get(), task_sets
));
236 completed_task_sets_
.reset();
237 tile_task_worker_pool_
->AsTileTaskRunner()->ScheduleTasks(&queue
);
240 void AppendTask(unsigned id
, const gfx::Size
& size
) {
241 scoped_ptr
<ScopedResource
> resource(
242 ScopedResource::Create(resource_provider_
.get()));
243 resource
->Allocate(size
, ResourceProvider::TEXTURE_HINT_IMMUTABLE
,
245 const Resource
* const_resource
= resource
.get();
247 ImageDecodeTask::Vector empty
;
248 tasks_
.push_back(new TestRasterTaskImpl(
250 base::Bind(&TileTaskWorkerPoolTest::OnTaskCompleted
,
251 base::Unretained(this), base::Passed(&resource
), id
),
255 void AppendTask(unsigned id
) { AppendTask(id
, gfx::Size(1, 1)); }
257 void AppendBlockingTask(unsigned id
, base::Lock
* lock
) {
258 const gfx::Size
size(1, 1);
260 scoped_ptr
<ScopedResource
> resource(
261 ScopedResource::Create(resource_provider_
.get()));
262 resource
->Allocate(size
, ResourceProvider::TEXTURE_HINT_IMMUTABLE
,
264 const Resource
* const_resource
= resource
.get();
266 ImageDecodeTask::Vector empty
;
267 tasks_
.push_back(new BlockingTestRasterTaskImpl(
269 base::Bind(&TileTaskWorkerPoolTest::OnTaskCompleted
,
270 base::Unretained(this), base::Passed(&resource
), id
),
274 const std::vector
<RasterTaskResult
>& completed_tasks() const {
275 return completed_tasks_
;
279 void Create3dOutputSurfaceAndResourceProvider() {
280 output_surface_
= FakeOutputSurface::Create3d(
281 context_provider_
, worker_context_provider_
).Pass();
282 CHECK(output_surface_
->BindToClient(&output_surface_client_
));
283 TestWebGraphicsContext3D
* context3d
= context_provider_
->TestContext3d();
284 context3d
->set_support_sync_query(true);
285 resource_provider_
= ResourceProvider::Create(output_surface_
.get(), NULL
,
286 &gpu_memory_buffer_manager_
,
287 NULL
, 0, false, 1).Pass();
290 void CreateSoftwareOutputSurfaceAndResourceProvider() {
291 output_surface_
= FakeOutputSurface::CreateSoftware(
292 make_scoped_ptr(new SoftwareOutputDevice
));
293 CHECK(output_surface_
->BindToClient(&output_surface_client_
));
295 ResourceProvider::Create(output_surface_
.get(), &shared_bitmap_manager_
,
296 NULL
, NULL
, 0, false, 1).Pass();
299 void OnTaskCompleted(scoped_ptr
<ScopedResource
> resource
,
301 const RasterSource::SolidColorAnalysis
& analysis
,
303 RasterTaskResult result
;
305 result
.canceled
= was_canceled
;
306 completed_tasks_
.push_back(result
);
311 base::MessageLoop::current()->Quit();
315 scoped_refptr
<TestContextProvider
> context_provider_
;
316 scoped_refptr
<TestContextProvider
> worker_context_provider_
;
317 scoped_ptr
<Rasterizer
> rasterizer_
;
318 FakeOutputSurfaceClient output_surface_client_
;
319 scoped_ptr
<FakeOutputSurface
> output_surface_
;
320 scoped_ptr
<ResourceProvider
> resource_provider_
;
321 scoped_ptr
<ResourcePool
> staging_resource_pool_
;
322 scoped_ptr
<TileTaskWorkerPool
> tile_task_worker_pool_
;
323 TestGpuMemoryBufferManager gpu_memory_buffer_manager_
;
324 TestSharedBitmapManager shared_bitmap_manager_
;
325 base::CancelableClosure timeout_
;
326 UniqueNotifier all_tile_tasks_finished_
;
327 int timeout_seconds_
;
329 RasterTaskVector tasks_
;
330 std::vector
<RasterTaskResult
> completed_tasks_
;
331 TaskSetCollection completed_task_sets_
;
334 TEST_P(TileTaskWorkerPoolTest
, Basic
) {
339 RunMessageLoopUntilAllTasksHaveCompleted();
341 ASSERT_EQ(2u, completed_tasks().size());
342 EXPECT_FALSE(completed_tasks()[0].canceled
);
343 EXPECT_FALSE(completed_tasks()[1].canceled
);
346 TEST_P(TileTaskWorkerPoolTest
, FailedMapResource
) {
347 if (GetParam() == TILE_TASK_WORKER_POOL_TYPE_BITMAP
)
350 TestWebGraphicsContext3D
* context3d
= context_provider_
->TestContext3d();
351 context3d
->set_times_map_buffer_chromium_succeeds(0);
355 RunMessageLoopUntilAllTasksHaveCompleted();
357 ASSERT_EQ(1u, completed_tasks().size());
358 EXPECT_FALSE(completed_tasks()[0].canceled
);
361 // This test checks that replacing a pending raster task with another does
362 // not prevent the DidFinishRunningTileTasks notification from being sent.
363 TEST_P(TileTaskWorkerPoolTest
, FalseThrottling
) {
366 // Schedule a task that is prevented from completing with a lock.
368 AppendBlockingTask(0u, &lock
);
371 // Schedule another task to replace the still-pending task. Because the old
372 // task is not a throttled task in the new task set, it should not prevent
373 // DidFinishRunningTileTasks from getting signaled.
374 RasterTaskVector tasks
;
379 // Unblock the first task to allow the second task to complete.
382 RunMessageLoopUntilAllTasksHaveCompleted();
385 TEST_P(TileTaskWorkerPoolTest
, LargeResources
) {
386 gfx::Size
size(kLargeResourceDimension
, kLargeResourceDimension
);
389 // Verify a resource of this size is larger than the transfer buffer.
390 scoped_ptr
<ScopedResource
> resource(
391 ScopedResource::Create(resource_provider_
.get()));
392 resource
->Allocate(size
, ResourceProvider::TEXTURE_HINT_IMMUTABLE
,
394 EXPECT_GE(resource
->bytes(), kMaxTransferBufferUsageBytes
);
397 AppendTask(0u, size
);
398 AppendTask(1u, size
);
399 AppendTask(2u, size
);
402 // This will time out if a resource that is larger than the throttle limit
403 // never gets scheduled.
404 RunMessageLoopUntilAllTasksHaveCompleted();
407 INSTANTIATE_TEST_CASE_P(
408 TileTaskWorkerPoolTests
,
409 TileTaskWorkerPoolTest
,
410 ::testing::Values(TILE_TASK_WORKER_POOL_TYPE_PIXEL_BUFFER
,
411 TILE_TASK_WORKER_POOL_TYPE_ZERO_COPY
,
412 TILE_TASK_WORKER_POOL_TYPE_ONE_COPY
,
413 TILE_TASK_WORKER_POOL_TYPE_GPU
,
414 TILE_TASK_WORKER_POOL_TYPE_BITMAP
));