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_task_graph_runner.h"
31 #include "cc/test/test_web_graphics_context_3d.h"
32 #include "gpu/GLES2/gl2extchromium.h"
33 #include "testing/gtest/include/gtest/gtest.h"
38 const size_t kMaxTransferBufferUsageBytes
= 10000U;
39 // A resource of this dimension^2 * 4 must be greater than the above transfer
41 const size_t kLargeResourceDimension
= 1000U;
43 enum TileTaskWorkerPoolType
{
44 TILE_TASK_WORKER_POOL_TYPE_PIXEL_BUFFER
,
45 TILE_TASK_WORKER_POOL_TYPE_ZERO_COPY
,
46 TILE_TASK_WORKER_POOL_TYPE_ONE_COPY
,
47 TILE_TASK_WORKER_POOL_TYPE_GPU
,
48 TILE_TASK_WORKER_POOL_TYPE_BITMAP
51 class TestRasterTaskImpl
: public RasterTask
{
53 typedef base::Callback
<void(const RasterSource::SolidColorAnalysis
& analysis
,
54 bool was_canceled
)> Reply
;
56 TestRasterTaskImpl(const Resource
* resource
,
58 ImageDecodeTask::Vector
* dependencies
)
59 : RasterTask(resource
, dependencies
),
61 picture_pile_(FakePicturePileImpl::CreateEmptyPile(gfx::Size(1, 1),
64 // Overridden from Task:
65 void RunOnWorkerThread() override
{
66 raster_buffer_
->Playback(picture_pile_
.get(), gfx::Rect(0, 0, 1, 1), 1.0);
69 // Overridden from TileTask:
70 void ScheduleOnOriginThread(TileTaskClient
* client
) override
{
71 raster_buffer_
= client
->AcquireBufferForRaster(resource());
73 void CompleteOnOriginThread(TileTaskClient
* client
) override
{
74 client
->ReleaseBufferForRaster(raster_buffer_
.Pass());
76 void RunReplyOnOriginThread() override
{
77 reply_
.Run(RasterSource::SolidColorAnalysis(), !HasFinishedRunning());
81 ~TestRasterTaskImpl() override
{}
85 scoped_ptr
<RasterBuffer
> raster_buffer_
;
86 scoped_refptr
<PicturePileImpl
> picture_pile_
;
88 DISALLOW_COPY_AND_ASSIGN(TestRasterTaskImpl
);
91 class BlockingTestRasterTaskImpl
: public TestRasterTaskImpl
{
93 BlockingTestRasterTaskImpl(const Resource
* resource
,
96 ImageDecodeTask::Vector
* dependencies
)
97 : TestRasterTaskImpl(resource
, reply
, dependencies
), lock_(lock
) {}
99 // Overridden from Task:
100 void RunOnWorkerThread() override
{
101 base::AutoLock
lock(*lock_
);
102 TestRasterTaskImpl::RunOnWorkerThread();
105 // Overridden from TileTask:
106 void RunReplyOnOriginThread() override
{}
109 ~BlockingTestRasterTaskImpl() override
{}
114 DISALLOW_COPY_AND_ASSIGN(BlockingTestRasterTaskImpl
);
117 class TileTaskWorkerPoolTest
118 : public testing::TestWithParam
<TileTaskWorkerPoolType
>,
119 public TileTaskRunnerClient
{
121 struct RasterTaskResult
{
126 typedef std::vector
<scoped_refptr
<RasterTask
>> RasterTaskVector
;
128 enum NamedTaskSet
{ REQUIRED_FOR_ACTIVATION
, REQUIRED_FOR_DRAW
, ALL
};
130 TileTaskWorkerPoolTest()
131 : context_provider_(TestContextProvider::Create()),
132 worker_context_provider_(TestContextProvider::Create()),
133 all_tile_tasks_finished_(
134 base::MessageLoopProxy::current().get(),
135 base::Bind(&TileTaskWorkerPoolTest::AllTileTasksFinished
,
136 base::Unretained(this))),
140 // Overridden from testing::Test:
141 void SetUp() override
{
142 switch (GetParam()) {
143 case TILE_TASK_WORKER_POOL_TYPE_PIXEL_BUFFER
:
144 Create3dOutputSurfaceAndResourceProvider();
145 tile_task_worker_pool_
= PixelBufferTileTaskWorkerPool::Create(
146 base::MessageLoopProxy::current().get(), &task_graph_runner_
,
147 context_provider_
.get(), resource_provider_
.get(),
148 kMaxTransferBufferUsageBytes
);
150 case TILE_TASK_WORKER_POOL_TYPE_ZERO_COPY
:
151 Create3dOutputSurfaceAndResourceProvider();
152 tile_task_worker_pool_
= ZeroCopyTileTaskWorkerPool::Create(
153 base::MessageLoopProxy::current().get(), &task_graph_runner_
,
154 resource_provider_
.get());
156 case TILE_TASK_WORKER_POOL_TYPE_ONE_COPY
:
157 Create3dOutputSurfaceAndResourceProvider();
158 staging_resource_pool_
= ResourcePool::Create(resource_provider_
.get(),
160 tile_task_worker_pool_
= OneCopyTileTaskWorkerPool::Create(
161 base::MessageLoopProxy::current().get(), &task_graph_runner_
,
162 context_provider_
.get(), resource_provider_
.get(),
163 staging_resource_pool_
.get());
165 case TILE_TASK_WORKER_POOL_TYPE_GPU
:
166 Create3dOutputSurfaceAndResourceProvider();
167 tile_task_worker_pool_
= GpuTileTaskWorkerPool::Create(
168 base::MessageLoopProxy::current().get(), &task_graph_runner_
,
169 context_provider_
.get(), resource_provider_
.get(), false, 0);
171 case TILE_TASK_WORKER_POOL_TYPE_BITMAP
:
172 CreateSoftwareOutputSurfaceAndResourceProvider();
173 tile_task_worker_pool_
= BitmapTileTaskWorkerPool::Create(
174 base::MessageLoopProxy::current().get(), &task_graph_runner_
,
175 resource_provider_
.get());
179 DCHECK(tile_task_worker_pool_
);
180 tile_task_worker_pool_
->AsTileTaskRunner()->SetClient(this);
183 void TearDown() override
{
184 tile_task_worker_pool_
->AsTileTaskRunner()->Shutdown();
185 tile_task_worker_pool_
->AsTileTaskRunner()->CheckForCompletedTasks();
188 void AllTileTasksFinished() {
189 tile_task_worker_pool_
->AsTileTaskRunner()->CheckForCompletedTasks();
190 base::MessageLoop::current()->Quit();
193 // Overriden from TileTaskWorkerPoolClient:
194 void DidFinishRunningTileTasks(TaskSet task_set
) override
{
195 EXPECT_FALSE(completed_task_sets_
[task_set
]);
196 completed_task_sets_
[task_set
] = true;
197 if (task_set
== ALL
) {
198 EXPECT_TRUE((~completed_task_sets_
).none());
199 all_tile_tasks_finished_
.Schedule();
203 TaskSetCollection
TasksThatShouldBeForcedToComplete() const override
{
204 return TaskSetCollection();
207 void RunMessageLoopUntilAllTasksHaveCompleted() {
208 if (timeout_seconds_
) {
209 timeout_
.Reset(base::Bind(&TileTaskWorkerPoolTest::OnTimeout
,
210 base::Unretained(this)));
211 base::MessageLoopProxy::current()->PostDelayedTask(
212 FROM_HERE
, timeout_
.callback(),
213 base::TimeDelta::FromSeconds(timeout_seconds_
));
216 base::MessageLoop::current()->Run();
220 ASSERT_FALSE(timed_out_
) << "Test timed out";
223 void ScheduleTasks() {
226 for (RasterTaskVector::const_iterator it
= tasks_
.begin();
227 it
!= tasks_
.end(); ++it
) {
228 TaskSetCollection task_sets
;
229 task_sets
[REQUIRED_FOR_ACTIVATION
] = true;
230 task_sets
[REQUIRED_FOR_DRAW
] = true;
231 task_sets
[ALL
] = true;
232 queue
.items
.push_back(TileTaskQueue::Item(it
->get(), task_sets
));
235 completed_task_sets_
.reset();
236 tile_task_worker_pool_
->AsTileTaskRunner()->ScheduleTasks(&queue
);
239 void AppendTask(unsigned id
, const gfx::Size
& size
) {
240 scoped_ptr
<ScopedResource
> resource(
241 ScopedResource::Create(resource_provider_
.get()));
242 resource
->Allocate(size
, ResourceProvider::TEXTURE_HINT_IMMUTABLE
,
244 const Resource
* const_resource
= resource
.get();
246 ImageDecodeTask::Vector empty
;
247 tasks_
.push_back(new TestRasterTaskImpl(
249 base::Bind(&TileTaskWorkerPoolTest::OnTaskCompleted
,
250 base::Unretained(this), base::Passed(&resource
), id
),
254 void AppendTask(unsigned id
) { AppendTask(id
, gfx::Size(1, 1)); }
256 void AppendBlockingTask(unsigned id
, base::Lock
* lock
) {
257 const gfx::Size
size(1, 1);
259 scoped_ptr
<ScopedResource
> resource(
260 ScopedResource::Create(resource_provider_
.get()));
261 resource
->Allocate(size
, ResourceProvider::TEXTURE_HINT_IMMUTABLE
,
263 const Resource
* const_resource
= resource
.get();
265 ImageDecodeTask::Vector empty
;
266 tasks_
.push_back(new BlockingTestRasterTaskImpl(
268 base::Bind(&TileTaskWorkerPoolTest::OnTaskCompleted
,
269 base::Unretained(this), base::Passed(&resource
), id
),
273 const std::vector
<RasterTaskResult
>& completed_tasks() const {
274 return completed_tasks_
;
277 void LoseContext(ContextProvider
* context_provider
) {
278 if (!context_provider
)
280 context_provider
->ContextGL()->LoseContextCHROMIUM(
281 GL_GUILTY_CONTEXT_RESET_ARB
, GL_INNOCENT_CONTEXT_RESET_ARB
);
282 context_provider
->ContextGL()->Flush();
286 void Create3dOutputSurfaceAndResourceProvider() {
287 output_surface_
= FakeOutputSurface::Create3d(
288 context_provider_
, worker_context_provider_
).Pass();
289 CHECK(output_surface_
->BindToClient(&output_surface_client_
));
290 TestWebGraphicsContext3D
* context3d
= context_provider_
->TestContext3d();
291 context3d
->set_support_sync_query(true);
292 resource_provider_
= ResourceProvider::Create(output_surface_
.get(), NULL
,
293 &gpu_memory_buffer_manager_
,
294 NULL
, 0, false, 1).Pass();
297 void CreateSoftwareOutputSurfaceAndResourceProvider() {
298 output_surface_
= FakeOutputSurface::CreateSoftware(
299 make_scoped_ptr(new SoftwareOutputDevice
));
300 CHECK(output_surface_
->BindToClient(&output_surface_client_
));
302 ResourceProvider::Create(output_surface_
.get(), &shared_bitmap_manager_
,
303 NULL
, NULL
, 0, false, 1).Pass();
306 void OnTaskCompleted(scoped_ptr
<ScopedResource
> resource
,
308 const RasterSource::SolidColorAnalysis
& analysis
,
310 RasterTaskResult result
;
312 result
.canceled
= was_canceled
;
313 completed_tasks_
.push_back(result
);
318 base::MessageLoop::current()->Quit();
322 scoped_refptr
<TestContextProvider
> context_provider_
;
323 scoped_refptr
<TestContextProvider
> worker_context_provider_
;
324 FakeOutputSurfaceClient output_surface_client_
;
325 scoped_ptr
<FakeOutputSurface
> output_surface_
;
326 scoped_ptr
<ResourceProvider
> resource_provider_
;
327 scoped_ptr
<ResourcePool
> staging_resource_pool_
;
328 scoped_ptr
<TileTaskWorkerPool
> tile_task_worker_pool_
;
329 TestGpuMemoryBufferManager gpu_memory_buffer_manager_
;
330 TestSharedBitmapManager shared_bitmap_manager_
;
331 TestTaskGraphRunner task_graph_runner_
;
332 base::CancelableClosure timeout_
;
333 UniqueNotifier all_tile_tasks_finished_
;
334 int timeout_seconds_
;
336 RasterTaskVector tasks_
;
337 std::vector
<RasterTaskResult
> completed_tasks_
;
338 TaskSetCollection completed_task_sets_
;
341 TEST_P(TileTaskWorkerPoolTest
, Basic
) {
346 RunMessageLoopUntilAllTasksHaveCompleted();
348 ASSERT_EQ(2u, completed_tasks().size());
349 EXPECT_FALSE(completed_tasks()[0].canceled
);
350 EXPECT_FALSE(completed_tasks()[1].canceled
);
353 TEST_P(TileTaskWorkerPoolTest
, FailedMapResource
) {
354 if (GetParam() == TILE_TASK_WORKER_POOL_TYPE_BITMAP
)
357 TestWebGraphicsContext3D
* context3d
= context_provider_
->TestContext3d();
358 context3d
->set_times_map_buffer_chromium_succeeds(0);
362 RunMessageLoopUntilAllTasksHaveCompleted();
364 ASSERT_EQ(1u, completed_tasks().size());
365 EXPECT_FALSE(completed_tasks()[0].canceled
);
368 // This test checks that replacing a pending raster task with another does
369 // not prevent the DidFinishRunningTileTasks notification from being sent.
370 TEST_P(TileTaskWorkerPoolTest
, FalseThrottling
) {
373 // Schedule a task that is prevented from completing with a lock.
375 AppendBlockingTask(0u, &lock
);
378 // Schedule another task to replace the still-pending task. Because the old
379 // task is not a throttled task in the new task set, it should not prevent
380 // DidFinishRunningTileTasks from getting signaled.
381 RasterTaskVector tasks
;
386 // Unblock the first task to allow the second task to complete.
389 RunMessageLoopUntilAllTasksHaveCompleted();
392 TEST_P(TileTaskWorkerPoolTest
, LargeResources
) {
393 gfx::Size
size(kLargeResourceDimension
, kLargeResourceDimension
);
396 // Verify a resource of this size is larger than the transfer buffer.
397 scoped_ptr
<ScopedResource
> resource(
398 ScopedResource::Create(resource_provider_
.get()));
399 resource
->Allocate(size
, ResourceProvider::TEXTURE_HINT_IMMUTABLE
,
401 EXPECT_GE(resource
->bytes(), kMaxTransferBufferUsageBytes
);
404 AppendTask(0u, size
);
405 AppendTask(1u, size
);
406 AppendTask(2u, size
);
409 // This will time out if a resource that is larger than the throttle limit
410 // never gets scheduled.
411 RunMessageLoopUntilAllTasksHaveCompleted();
414 TEST_P(TileTaskWorkerPoolTest
, LostContext
) {
415 LoseContext(output_surface_
->context_provider());
416 LoseContext(output_surface_
->worker_context_provider());
422 RunMessageLoopUntilAllTasksHaveCompleted();
424 ASSERT_EQ(2u, completed_tasks().size());
425 EXPECT_FALSE(completed_tasks()[0].canceled
);
426 EXPECT_FALSE(completed_tasks()[1].canceled
);
429 INSTANTIATE_TEST_CASE_P(
430 TileTaskWorkerPoolTests
,
431 TileTaskWorkerPoolTest
,
432 ::testing::Values(TILE_TASK_WORKER_POOL_TYPE_PIXEL_BUFFER
,
433 TILE_TASK_WORKER_POOL_TYPE_ZERO_COPY
,
434 TILE_TASK_WORKER_POOL_TYPE_ONE_COPY
,
435 TILE_TASK_WORKER_POOL_TYPE_GPU
,
436 TILE_TASK_WORKER_POOL_TYPE_BITMAP
));