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 "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/resources/bitmap_tile_task_worker_pool.h"
16 #include "cc/resources/gpu_rasterizer.h"
17 #include "cc/resources/gpu_tile_task_worker_pool.h"
18 #include "cc/resources/one_copy_tile_task_worker_pool.h"
19 #include "cc/resources/picture_pile.h"
20 #include "cc/resources/picture_pile_impl.h"
21 #include "cc/resources/pixel_buffer_tile_task_worker_pool.h"
22 #include "cc/resources/raster_buffer.h"
23 #include "cc/resources/resource_pool.h"
24 #include "cc/resources/resource_provider.h"
25 #include "cc/resources/scoped_resource.h"
26 #include "cc/resources/tile_task_runner.h"
27 #include "cc/resources/zero_copy_tile_task_worker_pool.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/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 kMaxTransferBufferUsageBytes
= 10000U;
42 // A resource of this dimension^2 * 4 must be greater than the above transfer
44 const size_t kLargeResourceDimension
= 1000U;
46 enum TileTaskWorkerPoolType
{
47 TILE_TASK_WORKER_POOL_TYPE_PIXEL_BUFFER
,
48 TILE_TASK_WORKER_POOL_TYPE_ZERO_COPY
,
49 TILE_TASK_WORKER_POOL_TYPE_ONE_COPY
,
50 TILE_TASK_WORKER_POOL_TYPE_GPU
,
51 TILE_TASK_WORKER_POOL_TYPE_BITMAP
54 class TestRasterTaskImpl
: public RasterTask
{
56 typedef base::Callback
<void(const RasterSource::SolidColorAnalysis
& analysis
,
57 bool was_canceled
)> Reply
;
59 TestRasterTaskImpl(const Resource
* resource
,
61 ImageDecodeTask::Vector
* dependencies
)
62 : RasterTask(resource
, dependencies
),
64 picture_pile_(FakePicturePileImpl::CreateEmptyPile(gfx::Size(1, 1),
67 // Overridden from Task:
68 void RunOnWorkerThread() override
{
69 raster_buffer_
->Playback(picture_pile_
.get(), gfx::Rect(0, 0, 1, 1), 1.0);
72 // Overridden from TileTask:
73 void ScheduleOnOriginThread(TileTaskClient
* client
) override
{
74 raster_buffer_
= client
->AcquireBufferForRaster(resource());
76 void CompleteOnOriginThread(TileTaskClient
* client
) override
{
77 client
->ReleaseBufferForRaster(raster_buffer_
.Pass());
79 void RunReplyOnOriginThread() override
{
80 reply_
.Run(RasterSource::SolidColorAnalysis(), !HasFinishedRunning());
84 ~TestRasterTaskImpl() override
{}
88 scoped_ptr
<RasterBuffer
> raster_buffer_
;
89 scoped_refptr
<PicturePileImpl
> picture_pile_
;
91 DISALLOW_COPY_AND_ASSIGN(TestRasterTaskImpl
);
94 class BlockingTestRasterTaskImpl
: public TestRasterTaskImpl
{
96 BlockingTestRasterTaskImpl(const Resource
* resource
,
99 ImageDecodeTask::Vector
* dependencies
)
100 : TestRasterTaskImpl(resource
, reply
, dependencies
), lock_(lock
) {}
102 // Overridden from Task:
103 void RunOnWorkerThread() override
{
104 base::AutoLock
lock(*lock_
);
105 TestRasterTaskImpl::RunOnWorkerThread();
108 // Overridden from TileTask:
109 void RunReplyOnOriginThread() override
{}
112 ~BlockingTestRasterTaskImpl() override
{}
117 DISALLOW_COPY_AND_ASSIGN(BlockingTestRasterTaskImpl
);
120 class TileTaskWorkerPoolTest
121 : public testing::TestWithParam
<TileTaskWorkerPoolType
>,
122 public TileTaskRunnerClient
{
124 struct RasterTaskResult
{
129 typedef std::vector
<scoped_refptr
<RasterTask
>> RasterTaskVector
;
131 enum NamedTaskSet
{ REQUIRED_FOR_ACTIVATION
, REQUIRED_FOR_DRAW
, ALL
};
133 TileTaskWorkerPoolTest()
134 : context_provider_(TestContextProvider::Create()),
135 worker_context_provider_(TestContextProvider::Create()),
136 all_tile_tasks_finished_(
137 base::ThreadTaskRunnerHandle::Get().get(),
138 base::Bind(&TileTaskWorkerPoolTest::AllTileTasksFinished
,
139 base::Unretained(this))),
143 // Overridden from testing::Test:
144 void SetUp() override
{
145 switch (GetParam()) {
146 case TILE_TASK_WORKER_POOL_TYPE_PIXEL_BUFFER
:
147 Create3dOutputSurfaceAndResourceProvider();
148 tile_task_worker_pool_
= PixelBufferTileTaskWorkerPool::Create(
149 base::ThreadTaskRunnerHandle::Get().get(), &task_graph_runner_
,
150 context_provider_
.get(), resource_provider_
.get(),
151 kMaxTransferBufferUsageBytes
);
153 case TILE_TASK_WORKER_POOL_TYPE_ZERO_COPY
:
154 Create3dOutputSurfaceAndResourceProvider();
155 tile_task_worker_pool_
= ZeroCopyTileTaskWorkerPool::Create(
156 base::ThreadTaskRunnerHandle::Get().get(), &task_graph_runner_
,
157 resource_provider_
.get());
159 case TILE_TASK_WORKER_POOL_TYPE_ONE_COPY
:
160 Create3dOutputSurfaceAndResourceProvider();
161 staging_resource_pool_
= ResourcePool::Create(resource_provider_
.get(),
163 tile_task_worker_pool_
= OneCopyTileTaskWorkerPool::Create(
164 base::ThreadTaskRunnerHandle::Get().get(), &task_graph_runner_
,
165 context_provider_
.get(), resource_provider_
.get(),
166 staging_resource_pool_
.get());
168 case TILE_TASK_WORKER_POOL_TYPE_GPU
:
169 Create3dOutputSurfaceAndResourceProvider();
170 tile_task_worker_pool_
= GpuTileTaskWorkerPool::Create(
171 base::ThreadTaskRunnerHandle::Get().get(), &task_graph_runner_
,
172 context_provider_
.get(), resource_provider_
.get(), false, 0);
174 case TILE_TASK_WORKER_POOL_TYPE_BITMAP
:
175 CreateSoftwareOutputSurfaceAndResourceProvider();
176 tile_task_worker_pool_
= BitmapTileTaskWorkerPool::Create(
177 base::ThreadTaskRunnerHandle::Get().get(), &task_graph_runner_
,
178 resource_provider_
.get());
182 DCHECK(tile_task_worker_pool_
);
183 tile_task_worker_pool_
->AsTileTaskRunner()->SetClient(this);
186 void TearDown() override
{
187 tile_task_worker_pool_
->AsTileTaskRunner()->Shutdown();
188 tile_task_worker_pool_
->AsTileTaskRunner()->CheckForCompletedTasks();
191 void AllTileTasksFinished() {
192 tile_task_worker_pool_
->AsTileTaskRunner()->CheckForCompletedTasks();
193 base::MessageLoop::current()->Quit();
196 // Overriden from TileTaskWorkerPoolClient:
197 void DidFinishRunningTileTasks(TaskSet task_set
) override
{
198 EXPECT_FALSE(completed_task_sets_
[task_set
]);
199 completed_task_sets_
[task_set
] = true;
200 if (task_set
== ALL
) {
201 EXPECT_TRUE((~completed_task_sets_
).none());
202 all_tile_tasks_finished_
.Schedule();
206 TaskSetCollection
TasksThatShouldBeForcedToComplete() const override
{
207 return TaskSetCollection();
210 void RunMessageLoopUntilAllTasksHaveCompleted() {
211 if (timeout_seconds_
) {
212 timeout_
.Reset(base::Bind(&TileTaskWorkerPoolTest::OnTimeout
,
213 base::Unretained(this)));
214 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
215 FROM_HERE
, timeout_
.callback(),
216 base::TimeDelta::FromSeconds(timeout_seconds_
));
219 base::MessageLoop::current()->Run();
223 ASSERT_FALSE(timed_out_
) << "Test timed out";
226 void ScheduleTasks() {
229 for (RasterTaskVector::const_iterator it
= tasks_
.begin();
230 it
!= tasks_
.end(); ++it
) {
231 TaskSetCollection task_sets
;
232 task_sets
[REQUIRED_FOR_ACTIVATION
] = true;
233 task_sets
[REQUIRED_FOR_DRAW
] = true;
234 task_sets
[ALL
] = true;
235 queue
.items
.push_back(TileTaskQueue::Item(it
->get(), task_sets
));
238 completed_task_sets_
.reset();
239 tile_task_worker_pool_
->AsTileTaskRunner()->ScheduleTasks(&queue
);
242 void AppendTask(unsigned id
, const gfx::Size
& size
) {
243 scoped_ptr
<ScopedResource
> resource(
244 ScopedResource::Create(resource_provider_
.get()));
245 resource
->Allocate(size
, ResourceProvider::TEXTURE_HINT_IMMUTABLE
,
247 const Resource
* const_resource
= resource
.get();
249 ImageDecodeTask::Vector empty
;
250 tasks_
.push_back(new TestRasterTaskImpl(
252 base::Bind(&TileTaskWorkerPoolTest::OnTaskCompleted
,
253 base::Unretained(this), base::Passed(&resource
), id
),
257 void AppendTask(unsigned id
) { AppendTask(id
, gfx::Size(1, 1)); }
259 void AppendBlockingTask(unsigned id
, base::Lock
* lock
) {
260 const gfx::Size
size(1, 1);
262 scoped_ptr
<ScopedResource
> resource(
263 ScopedResource::Create(resource_provider_
.get()));
264 resource
->Allocate(size
, ResourceProvider::TEXTURE_HINT_IMMUTABLE
,
266 const Resource
* const_resource
= resource
.get();
268 ImageDecodeTask::Vector empty
;
269 tasks_
.push_back(new BlockingTestRasterTaskImpl(
271 base::Bind(&TileTaskWorkerPoolTest::OnTaskCompleted
,
272 base::Unretained(this), base::Passed(&resource
), id
),
276 const std::vector
<RasterTaskResult
>& completed_tasks() const {
277 return completed_tasks_
;
280 void LoseContext(ContextProvider
* context_provider
) {
281 if (!context_provider
)
283 context_provider
->ContextGL()->LoseContextCHROMIUM(
284 GL_GUILTY_CONTEXT_RESET_ARB
, GL_INNOCENT_CONTEXT_RESET_ARB
);
285 context_provider
->ContextGL()->Flush();
289 void Create3dOutputSurfaceAndResourceProvider() {
290 output_surface_
= FakeOutputSurface::Create3d(
291 context_provider_
, worker_context_provider_
).Pass();
292 CHECK(output_surface_
->BindToClient(&output_surface_client_
));
293 TestWebGraphicsContext3D
* context3d
= context_provider_
->TestContext3d();
294 context3d
->set_support_sync_query(true);
295 resource_provider_
= ResourceProvider::Create(output_surface_
.get(), NULL
,
296 &gpu_memory_buffer_manager_
,
297 NULL
, 0, false, 1).Pass();
300 void CreateSoftwareOutputSurfaceAndResourceProvider() {
301 output_surface_
= FakeOutputSurface::CreateSoftware(
302 make_scoped_ptr(new SoftwareOutputDevice
));
303 CHECK(output_surface_
->BindToClient(&output_surface_client_
));
305 ResourceProvider::Create(output_surface_
.get(), &shared_bitmap_manager_
,
306 NULL
, NULL
, 0, false, 1).Pass();
309 void OnTaskCompleted(scoped_ptr
<ScopedResource
> resource
,
311 const RasterSource::SolidColorAnalysis
& analysis
,
313 RasterTaskResult result
;
315 result
.canceled
= was_canceled
;
316 completed_tasks_
.push_back(result
);
321 base::MessageLoop::current()->Quit();
325 scoped_refptr
<TestContextProvider
> context_provider_
;
326 scoped_refptr
<TestContextProvider
> worker_context_provider_
;
327 FakeOutputSurfaceClient output_surface_client_
;
328 scoped_ptr
<FakeOutputSurface
> output_surface_
;
329 scoped_ptr
<ResourceProvider
> resource_provider_
;
330 scoped_ptr
<ResourcePool
> staging_resource_pool_
;
331 scoped_ptr
<TileTaskWorkerPool
> tile_task_worker_pool_
;
332 TestGpuMemoryBufferManager gpu_memory_buffer_manager_
;
333 TestSharedBitmapManager shared_bitmap_manager_
;
334 TestTaskGraphRunner task_graph_runner_
;
335 base::CancelableClosure timeout_
;
336 UniqueNotifier all_tile_tasks_finished_
;
337 int timeout_seconds_
;
339 RasterTaskVector tasks_
;
340 std::vector
<RasterTaskResult
> completed_tasks_
;
341 TaskSetCollection completed_task_sets_
;
344 TEST_P(TileTaskWorkerPoolTest
, Basic
) {
349 RunMessageLoopUntilAllTasksHaveCompleted();
351 ASSERT_EQ(2u, completed_tasks().size());
352 EXPECT_FALSE(completed_tasks()[0].canceled
);
353 EXPECT_FALSE(completed_tasks()[1].canceled
);
356 TEST_P(TileTaskWorkerPoolTest
, FailedMapResource
) {
357 if (GetParam() == TILE_TASK_WORKER_POOL_TYPE_BITMAP
)
360 TestWebGraphicsContext3D
* context3d
= context_provider_
->TestContext3d();
361 context3d
->set_times_map_buffer_chromium_succeeds(0);
365 RunMessageLoopUntilAllTasksHaveCompleted();
367 ASSERT_EQ(1u, completed_tasks().size());
368 EXPECT_FALSE(completed_tasks()[0].canceled
);
371 // This test checks that replacing a pending raster task with another does
372 // not prevent the DidFinishRunningTileTasks notification from being sent.
373 TEST_P(TileTaskWorkerPoolTest
, FalseThrottling
) {
376 // Schedule a task that is prevented from completing with a lock.
378 AppendBlockingTask(0u, &lock
);
381 // Schedule another task to replace the still-pending task. Because the old
382 // task is not a throttled task in the new task set, it should not prevent
383 // DidFinishRunningTileTasks from getting signaled.
384 RasterTaskVector tasks
;
389 // Unblock the first task to allow the second task to complete.
392 RunMessageLoopUntilAllTasksHaveCompleted();
395 TEST_P(TileTaskWorkerPoolTest
, LargeResources
) {
396 gfx::Size
size(kLargeResourceDimension
, kLargeResourceDimension
);
399 // Verify a resource of this size is larger than the transfer buffer.
400 scoped_ptr
<ScopedResource
> resource(
401 ScopedResource::Create(resource_provider_
.get()));
402 resource
->Allocate(size
, ResourceProvider::TEXTURE_HINT_IMMUTABLE
,
404 EXPECT_GE(resource
->bytes(), kMaxTransferBufferUsageBytes
);
407 AppendTask(0u, size
);
408 AppendTask(1u, size
);
409 AppendTask(2u, size
);
412 // This will time out if a resource that is larger than the throttle limit
413 // never gets scheduled.
414 RunMessageLoopUntilAllTasksHaveCompleted();
417 TEST_P(TileTaskWorkerPoolTest
, LostContext
) {
418 LoseContext(output_surface_
->context_provider());
419 LoseContext(output_surface_
->worker_context_provider());
425 RunMessageLoopUntilAllTasksHaveCompleted();
427 ASSERT_EQ(2u, completed_tasks().size());
428 EXPECT_FALSE(completed_tasks()[0].canceled
);
429 EXPECT_FALSE(completed_tasks()[1].canceled
);
432 INSTANTIATE_TEST_CASE_P(
433 TileTaskWorkerPoolTests
,
434 TileTaskWorkerPoolTest
,
435 ::testing::Values(TILE_TASK_WORKER_POOL_TYPE_PIXEL_BUFFER
,
436 TILE_TASK_WORKER_POOL_TYPE_ZERO_COPY
,
437 TILE_TASK_WORKER_POOL_TYPE_ONE_COPY
,
438 TILE_TASK_WORKER_POOL_TYPE_GPU
,
439 TILE_TASK_WORKER_POOL_TYPE_BITMAP
));