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;
45 // A resource of this dimension^2 * 4 must be greater than the above transfer
47 const size_t kLargeResourceDimension
= 1000U;
49 enum TileTaskWorkerPoolType
{
50 TILE_TASK_WORKER_POOL_TYPE_PIXEL_BUFFER
,
51 TILE_TASK_WORKER_POOL_TYPE_ZERO_COPY
,
52 TILE_TASK_WORKER_POOL_TYPE_ONE_COPY
,
53 TILE_TASK_WORKER_POOL_TYPE_GPU
,
54 TILE_TASK_WORKER_POOL_TYPE_BITMAP
57 class TestRasterTaskImpl
: public RasterTask
{
59 typedef base::Callback
<void(const RasterSource::SolidColorAnalysis
& analysis
,
60 bool was_canceled
)> Reply
;
62 TestRasterTaskImpl(const Resource
* resource
,
64 ImageDecodeTask::Vector
* dependencies
)
65 : RasterTask(resource
, dependencies
),
67 picture_pile_(FakePicturePileImpl::CreateEmptyPile(gfx::Size(1, 1),
70 // Overridden from Task:
71 void RunOnWorkerThread() override
{
72 uint64_t new_content_id
= 0;
73 raster_buffer_
->Playback(picture_pile_
.get(), gfx::Rect(1, 1),
74 gfx::Rect(1, 1), new_content_id
, 1.f
, true);
77 // Overridden from TileTask:
78 void ScheduleOnOriginThread(TileTaskClient
* client
) override
{
79 // The raster buffer has no tile ids associated with it for partial update,
80 // so doesn't need to provide a valid dirty rect.
81 raster_buffer_
= client
->AcquireBufferForRaster(resource(), 0, 0);
83 void CompleteOnOriginThread(TileTaskClient
* client
) override
{
84 client
->ReleaseBufferForRaster(raster_buffer_
.Pass());
86 void RunReplyOnOriginThread() override
{
87 reply_
.Run(RasterSource::SolidColorAnalysis(), !HasFinishedRunning());
91 ~TestRasterTaskImpl() override
{}
95 scoped_ptr
<RasterBuffer
> raster_buffer_
;
96 scoped_refptr
<PicturePileImpl
> picture_pile_
;
98 DISALLOW_COPY_AND_ASSIGN(TestRasterTaskImpl
);
101 class BlockingTestRasterTaskImpl
: public TestRasterTaskImpl
{
103 BlockingTestRasterTaskImpl(const Resource
* resource
,
106 ImageDecodeTask::Vector
* dependencies
)
107 : TestRasterTaskImpl(resource
, reply
, dependencies
), lock_(lock
) {}
109 // Overridden from Task:
110 void RunOnWorkerThread() override
{
111 base::AutoLock
lock(*lock_
);
112 TestRasterTaskImpl::RunOnWorkerThread();
115 // Overridden from TileTask:
116 void RunReplyOnOriginThread() override
{}
119 ~BlockingTestRasterTaskImpl() override
{}
124 DISALLOW_COPY_AND_ASSIGN(BlockingTestRasterTaskImpl
);
127 class TileTaskWorkerPoolTest
128 : public testing::TestWithParam
<TileTaskWorkerPoolType
>,
129 public TileTaskRunnerClient
{
131 struct RasterTaskResult
{
136 typedef std::vector
<scoped_refptr
<RasterTask
>> RasterTaskVector
;
138 enum NamedTaskSet
{ REQUIRED_FOR_ACTIVATION
, REQUIRED_FOR_DRAW
, ALL
};
140 TileTaskWorkerPoolTest()
141 : context_provider_(TestContextProvider::Create()),
142 worker_context_provider_(TestContextProvider::Create()),
143 all_tile_tasks_finished_(
144 base::ThreadTaskRunnerHandle::Get().get(),
145 base::Bind(&TileTaskWorkerPoolTest::AllTileTasksFinished
,
146 base::Unretained(this))),
150 // Overridden from testing::Test:
151 void SetUp() override
{
152 switch (GetParam()) {
153 case TILE_TASK_WORKER_POOL_TYPE_PIXEL_BUFFER
:
154 Create3dOutputSurfaceAndResourceProvider();
155 tile_task_worker_pool_
= PixelBufferTileTaskWorkerPool::Create(
156 base::ThreadTaskRunnerHandle::Get().get(), &task_graph_runner_
,
157 context_provider_
.get(), resource_provider_
.get(),
158 kMaxTransferBufferUsageBytes
);
160 case TILE_TASK_WORKER_POOL_TYPE_ZERO_COPY
:
161 Create3dOutputSurfaceAndResourceProvider();
162 tile_task_worker_pool_
= ZeroCopyTileTaskWorkerPool::Create(
163 base::ThreadTaskRunnerHandle::Get().get(), &task_graph_runner_
,
164 resource_provider_
.get());
166 case TILE_TASK_WORKER_POOL_TYPE_ONE_COPY
:
167 Create3dOutputSurfaceAndResourceProvider();
168 staging_resource_pool_
= ResourcePool::Create(resource_provider_
.get(),
170 tile_task_worker_pool_
= OneCopyTileTaskWorkerPool::Create(
171 base::ThreadTaskRunnerHandle::Get().get(), &task_graph_runner_
,
172 context_provider_
.get(), resource_provider_
.get(),
173 staging_resource_pool_
.get(), kMaxBytesPerCopyOperation
, false);
175 case TILE_TASK_WORKER_POOL_TYPE_GPU
:
176 Create3dOutputSurfaceAndResourceProvider();
177 tile_task_worker_pool_
= GpuTileTaskWorkerPool::Create(
178 base::ThreadTaskRunnerHandle::Get().get(), &task_graph_runner_
,
179 context_provider_
.get(), resource_provider_
.get(), false, 0);
181 case TILE_TASK_WORKER_POOL_TYPE_BITMAP
:
182 CreateSoftwareOutputSurfaceAndResourceProvider();
183 tile_task_worker_pool_
= BitmapTileTaskWorkerPool::Create(
184 base::ThreadTaskRunnerHandle::Get().get(), &task_graph_runner_
,
185 resource_provider_
.get());
189 DCHECK(tile_task_worker_pool_
);
190 tile_task_worker_pool_
->AsTileTaskRunner()->SetClient(this);
193 void TearDown() override
{
194 tile_task_worker_pool_
->AsTileTaskRunner()->Shutdown();
195 tile_task_worker_pool_
->AsTileTaskRunner()->CheckForCompletedTasks();
198 void AllTileTasksFinished() {
199 tile_task_worker_pool_
->AsTileTaskRunner()->CheckForCompletedTasks();
200 base::MessageLoop::current()->Quit();
203 // Overriden from TileTaskWorkerPoolClient:
204 void DidFinishRunningTileTasks(TaskSet task_set
) override
{
205 EXPECT_FALSE(completed_task_sets_
[task_set
]);
206 completed_task_sets_
[task_set
] = true;
207 if (task_set
== ALL
) {
208 EXPECT_TRUE((~completed_task_sets_
).none());
209 all_tile_tasks_finished_
.Schedule();
213 TaskSetCollection
TasksThatShouldBeForcedToComplete() const override
{
214 return TaskSetCollection();
217 void RunMessageLoopUntilAllTasksHaveCompleted() {
218 if (timeout_seconds_
) {
219 timeout_
.Reset(base::Bind(&TileTaskWorkerPoolTest::OnTimeout
,
220 base::Unretained(this)));
221 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
222 FROM_HERE
, timeout_
.callback(),
223 base::TimeDelta::FromSeconds(timeout_seconds_
));
226 base::MessageLoop::current()->Run();
230 ASSERT_FALSE(timed_out_
) << "Test timed out";
233 void ScheduleTasks() {
236 for (RasterTaskVector::const_iterator it
= tasks_
.begin();
237 it
!= tasks_
.end(); ++it
) {
238 TaskSetCollection task_sets
;
239 task_sets
[REQUIRED_FOR_ACTIVATION
] = true;
240 task_sets
[REQUIRED_FOR_DRAW
] = true;
241 task_sets
[ALL
] = true;
242 queue
.items
.push_back(TileTaskQueue::Item(it
->get(), task_sets
));
245 completed_task_sets_
.reset();
246 tile_task_worker_pool_
->AsTileTaskRunner()->ScheduleTasks(&queue
);
249 void AppendTask(unsigned id
, const gfx::Size
& size
) {
250 scoped_ptr
<ScopedResource
> resource(
251 ScopedResource::Create(resource_provider_
.get()));
252 resource
->Allocate(size
, ResourceProvider::TEXTURE_HINT_IMMUTABLE
,
254 const Resource
* const_resource
= resource
.get();
256 ImageDecodeTask::Vector empty
;
257 tasks_
.push_back(new TestRasterTaskImpl(
259 base::Bind(&TileTaskWorkerPoolTest::OnTaskCompleted
,
260 base::Unretained(this), base::Passed(&resource
), id
),
264 void AppendTask(unsigned id
) { AppendTask(id
, gfx::Size(1, 1)); }
266 void AppendBlockingTask(unsigned id
, base::Lock
* lock
) {
267 const gfx::Size
size(1, 1);
269 scoped_ptr
<ScopedResource
> resource(
270 ScopedResource::Create(resource_provider_
.get()));
271 resource
->Allocate(size
, ResourceProvider::TEXTURE_HINT_IMMUTABLE
,
273 const Resource
* const_resource
= resource
.get();
275 ImageDecodeTask::Vector empty
;
276 tasks_
.push_back(new BlockingTestRasterTaskImpl(
278 base::Bind(&TileTaskWorkerPoolTest::OnTaskCompleted
,
279 base::Unretained(this), base::Passed(&resource
), id
),
283 const std::vector
<RasterTaskResult
>& completed_tasks() const {
284 return completed_tasks_
;
287 void LoseContext(ContextProvider
* context_provider
) {
288 if (!context_provider
)
290 context_provider
->ContextGL()->LoseContextCHROMIUM(
291 GL_GUILTY_CONTEXT_RESET_ARB
, GL_INNOCENT_CONTEXT_RESET_ARB
);
292 context_provider
->ContextGL()->Flush();
296 void Create3dOutputSurfaceAndResourceProvider() {
297 output_surface_
= FakeOutputSurface::Create3d(context_provider_
,
298 worker_context_provider_
);
299 CHECK(output_surface_
->BindToClient(&output_surface_client_
));
300 TestWebGraphicsContext3D
* context3d
= context_provider_
->TestContext3d();
301 context3d
->set_support_sync_query(true);
302 resource_provider_
= FakeResourceProvider::Create(
303 output_surface_
.get(), nullptr, &gpu_memory_buffer_manager_
);
306 void CreateSoftwareOutputSurfaceAndResourceProvider() {
307 output_surface_
= FakeOutputSurface::CreateSoftware(
308 make_scoped_ptr(new SoftwareOutputDevice
));
309 CHECK(output_surface_
->BindToClient(&output_surface_client_
));
310 resource_provider_
= FakeResourceProvider::Create(
311 output_surface_
.get(), &shared_bitmap_manager_
, nullptr);
314 void OnTaskCompleted(scoped_ptr
<ScopedResource
> resource
,
316 const RasterSource::SolidColorAnalysis
& analysis
,
318 RasterTaskResult result
;
320 result
.canceled
= was_canceled
;
321 completed_tasks_
.push_back(result
);
326 base::MessageLoop::current()->Quit();
330 scoped_refptr
<TestContextProvider
> context_provider_
;
331 scoped_refptr
<TestContextProvider
> worker_context_provider_
;
332 FakeOutputSurfaceClient output_surface_client_
;
333 scoped_ptr
<FakeOutputSurface
> output_surface_
;
334 scoped_ptr
<ResourceProvider
> resource_provider_
;
335 scoped_ptr
<ResourcePool
> staging_resource_pool_
;
336 scoped_ptr
<TileTaskWorkerPool
> tile_task_worker_pool_
;
337 TestGpuMemoryBufferManager gpu_memory_buffer_manager_
;
338 TestSharedBitmapManager shared_bitmap_manager_
;
339 TestTaskGraphRunner task_graph_runner_
;
340 base::CancelableClosure timeout_
;
341 UniqueNotifier all_tile_tasks_finished_
;
342 int timeout_seconds_
;
344 RasterTaskVector tasks_
;
345 std::vector
<RasterTaskResult
> completed_tasks_
;
346 TaskSetCollection completed_task_sets_
;
349 TEST_P(TileTaskWorkerPoolTest
, Basic
) {
354 RunMessageLoopUntilAllTasksHaveCompleted();
356 ASSERT_EQ(2u, completed_tasks().size());
357 EXPECT_FALSE(completed_tasks()[0].canceled
);
358 EXPECT_FALSE(completed_tasks()[1].canceled
);
361 TEST_P(TileTaskWorkerPoolTest
, FailedMapResource
) {
362 if (GetParam() == TILE_TASK_WORKER_POOL_TYPE_BITMAP
)
365 TestWebGraphicsContext3D
* context3d
= context_provider_
->TestContext3d();
366 context3d
->set_times_map_buffer_chromium_succeeds(0);
370 RunMessageLoopUntilAllTasksHaveCompleted();
372 ASSERT_EQ(1u, completed_tasks().size());
373 EXPECT_FALSE(completed_tasks()[0].canceled
);
376 // This test checks that replacing a pending raster task with another does
377 // not prevent the DidFinishRunningTileTasks notification from being sent.
378 TEST_P(TileTaskWorkerPoolTest
, FalseThrottling
) {
381 // Schedule a task that is prevented from completing with a lock.
383 AppendBlockingTask(0u, &lock
);
386 // Schedule another task to replace the still-pending task. Because the old
387 // task is not a throttled task in the new task set, it should not prevent
388 // DidFinishRunningTileTasks from getting signaled.
389 RasterTaskVector tasks
;
394 // Unblock the first task to allow the second task to complete.
397 RunMessageLoopUntilAllTasksHaveCompleted();
400 TEST_P(TileTaskWorkerPoolTest
, LargeResources
) {
401 gfx::Size
size(kLargeResourceDimension
, kLargeResourceDimension
);
404 // Verify a resource of this size is larger than the transfer buffer.
405 scoped_ptr
<ScopedResource
> resource(
406 ScopedResource::Create(resource_provider_
.get()));
407 resource
->Allocate(size
, ResourceProvider::TEXTURE_HINT_IMMUTABLE
,
409 EXPECT_GE(ResourceUtil::UncheckedSizeInBytes
<size_t>(resource
->size(),
411 kMaxTransferBufferUsageBytes
);
414 AppendTask(0u, size
);
415 AppendTask(1u, size
);
416 AppendTask(2u, size
);
419 // This will time out if a resource that is larger than the throttle limit
420 // never gets scheduled.
421 RunMessageLoopUntilAllTasksHaveCompleted();
424 TEST_P(TileTaskWorkerPoolTest
, LostContext
) {
425 LoseContext(output_surface_
->context_provider());
426 LoseContext(output_surface_
->worker_context_provider());
432 RunMessageLoopUntilAllTasksHaveCompleted();
434 ASSERT_EQ(2u, completed_tasks().size());
435 EXPECT_FALSE(completed_tasks()[0].canceled
);
436 EXPECT_FALSE(completed_tasks()[1].canceled
);
439 TEST_P(TileTaskWorkerPoolTest
, ScheduleEmptyStillTriggersCallback
) {
440 // Don't append any tasks, just call ScheduleTasks.
443 EXPECT_FALSE(completed_task_sets_
[REQUIRED_FOR_ACTIVATION
]);
444 EXPECT_FALSE(completed_task_sets_
[REQUIRED_FOR_DRAW
]);
445 EXPECT_FALSE(completed_task_sets_
[ALL
]);
447 RunMessageLoopUntilAllTasksHaveCompleted();
449 EXPECT_TRUE(completed_task_sets_
[REQUIRED_FOR_ACTIVATION
]);
450 EXPECT_TRUE(completed_task_sets_
[REQUIRED_FOR_DRAW
]);
451 EXPECT_TRUE(completed_task_sets_
[ALL
]);
454 INSTANTIATE_TEST_CASE_P(
455 TileTaskWorkerPoolTests
,
456 TileTaskWorkerPoolTest
,
457 ::testing::Values(TILE_TASK_WORKER_POOL_TYPE_PIXEL_BUFFER
,
458 TILE_TASK_WORKER_POOL_TYPE_ZERO_COPY
,
459 TILE_TASK_WORKER_POOL_TYPE_ONE_COPY
,
460 TILE_TASK_WORKER_POOL_TYPE_GPU
,
461 TILE_TASK_WORKER_POOL_TYPE_BITMAP
));