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/raster_worker_pool.h"
10 #include "base/cancelable_callback.h"
11 #include "cc/resources/bitmap_raster_worker_pool.h"
12 #include "cc/resources/gpu_raster_worker_pool.h"
13 #include "cc/resources/one_copy_raster_worker_pool.h"
14 #include "cc/resources/picture_pile.h"
15 #include "cc/resources/picture_pile_impl.h"
16 #include "cc/resources/pixel_buffer_raster_worker_pool.h"
17 #include "cc/resources/raster_buffer.h"
18 #include "cc/resources/rasterizer.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/zero_copy_raster_worker_pool.h"
23 #include "cc/test/fake_output_surface.h"
24 #include "cc/test/fake_output_surface_client.h"
25 #include "cc/test/fake_picture_pile_impl.h"
26 #include "cc/test/test_gpu_memory_buffer_manager.h"
27 #include "cc/test/test_shared_bitmap_manager.h"
28 #include "cc/test/test_web_graphics_context_3d.h"
29 #include "testing/gtest/include/gtest/gtest.h"
34 const size_t kMaxTransferBufferUsageBytes
= 10000U;
35 // A resource of this dimension^2 * 4 must be greater than the above transfer
37 const size_t kLargeResourceDimension
= 1000U;
39 enum RasterWorkerPoolType
{
40 RASTER_WORKER_POOL_TYPE_PIXEL_BUFFER
,
41 RASTER_WORKER_POOL_TYPE_ZERO_COPY
,
42 RASTER_WORKER_POOL_TYPE_ONE_COPY
,
43 RASTER_WORKER_POOL_TYPE_GPU
,
44 RASTER_WORKER_POOL_TYPE_BITMAP
47 class TestRasterTaskImpl
: public RasterTask
{
49 typedef base::Callback
<void(const RasterSource::SolidColorAnalysis
& analysis
,
50 bool was_canceled
)> Reply
;
52 TestRasterTaskImpl(const Resource
* resource
,
54 ImageDecodeTask::Vector
* dependencies
)
55 : RasterTask(resource
, dependencies
),
57 picture_pile_(FakePicturePileImpl::CreateEmptyPile(gfx::Size(1, 1),
60 // Overridden from Task:
61 void RunOnWorkerThread() override
{
62 raster_buffer_
->Playback(picture_pile_
.get(), gfx::Rect(0, 0, 1, 1), 1.0);
65 // Overridden from RasterizerTask:
66 void ScheduleOnOriginThread(RasterizerTaskClient
* client
) override
{
67 raster_buffer_
= client
->AcquireBufferForRaster(resource());
69 void CompleteOnOriginThread(RasterizerTaskClient
* client
) override
{
70 client
->ReleaseBufferForRaster(raster_buffer_
.Pass());
72 void RunReplyOnOriginThread() override
{
73 reply_
.Run(RasterSource::SolidColorAnalysis(), !HasFinishedRunning());
77 ~TestRasterTaskImpl() override
{}
81 scoped_ptr
<RasterBuffer
> raster_buffer_
;
82 scoped_refptr
<PicturePileImpl
> picture_pile_
;
84 DISALLOW_COPY_AND_ASSIGN(TestRasterTaskImpl
);
87 class BlockingTestRasterTaskImpl
: public TestRasterTaskImpl
{
89 BlockingTestRasterTaskImpl(const Resource
* resource
,
92 ImageDecodeTask::Vector
* dependencies
)
93 : TestRasterTaskImpl(resource
, reply
, dependencies
), lock_(lock
) {}
95 // Overridden from Task:
96 void RunOnWorkerThread() override
{
97 base::AutoLock
lock(*lock_
);
98 TestRasterTaskImpl::RunOnWorkerThread();
101 // Overridden from RasterizerTask:
102 void RunReplyOnOriginThread() override
{}
105 ~BlockingTestRasterTaskImpl() override
{}
110 DISALLOW_COPY_AND_ASSIGN(BlockingTestRasterTaskImpl
);
113 class RasterWorkerPoolTest
114 : public testing::TestWithParam
<RasterWorkerPoolType
>,
115 public RasterizerClient
{
117 struct RasterTaskResult
{
122 typedef std::vector
<scoped_refptr
<RasterTask
>> RasterTaskVector
;
124 enum NamedTaskSet
{ ALL
, REQUIRED_FOR_ACTIVATION
, REQUIRED_FOR_DRAW
};
126 RasterWorkerPoolTest()
127 : context_provider_(TestContextProvider::Create()),
131 // Overridden from testing::Test:
132 void SetUp() override
{
133 switch (GetParam()) {
134 case RASTER_WORKER_POOL_TYPE_PIXEL_BUFFER
:
135 Create3dOutputSurfaceAndResourceProvider();
136 raster_worker_pool_
= PixelBufferRasterWorkerPool::Create(
137 base::MessageLoopProxy::current().get(),
138 RasterWorkerPool::GetTaskGraphRunner(),
139 context_provider_
.get(),
140 resource_provider_
.get(),
141 kMaxTransferBufferUsageBytes
);
143 case RASTER_WORKER_POOL_TYPE_ZERO_COPY
:
144 Create3dOutputSurfaceAndResourceProvider();
145 raster_worker_pool_
= ZeroCopyRasterWorkerPool::Create(
146 base::MessageLoopProxy::current().get(),
147 RasterWorkerPool::GetTaskGraphRunner(),
148 resource_provider_
.get());
150 case RASTER_WORKER_POOL_TYPE_ONE_COPY
:
151 Create3dOutputSurfaceAndResourceProvider();
152 staging_resource_pool_
= ResourcePool::Create(
153 resource_provider_
.get(), GL_TEXTURE_2D
, RGBA_8888
);
154 raster_worker_pool_
= OneCopyRasterWorkerPool::Create(
155 base::MessageLoopProxy::current().get(),
156 RasterWorkerPool::GetTaskGraphRunner(),
157 context_provider_
.get(),
158 resource_provider_
.get(),
159 staging_resource_pool_
.get());
161 case RASTER_WORKER_POOL_TYPE_GPU
:
162 Create3dOutputSurfaceAndResourceProvider();
163 raster_worker_pool_
=
164 GpuRasterWorkerPool::Create(base::MessageLoopProxy::current().get(),
165 context_provider_
.get(),
166 resource_provider_
.get(),
169 case RASTER_WORKER_POOL_TYPE_BITMAP
:
170 CreateSoftwareOutputSurfaceAndResourceProvider();
171 raster_worker_pool_
= BitmapRasterWorkerPool::Create(
172 base::MessageLoopProxy::current().get(),
173 RasterWorkerPool::GetTaskGraphRunner(),
174 resource_provider_
.get());
178 DCHECK(raster_worker_pool_
);
179 raster_worker_pool_
->AsRasterizer()->SetClient(this);
182 void TearDown() override
{
183 raster_worker_pool_
->AsRasterizer()->Shutdown();
184 raster_worker_pool_
->AsRasterizer()->CheckForCompletedTasks();
187 // Overriden from RasterWorkerPoolClient:
188 void DidFinishRunningTasks(TaskSet task_set
) override
{
189 if (task_set
== ALL
) {
190 raster_worker_pool_
->AsRasterizer()->CheckForCompletedTasks();
191 base::MessageLoop::current()->Quit();
194 TaskSetCollection
TasksThatShouldBeForcedToComplete() const override
{
195 return TaskSetCollection();
198 void RunMessageLoopUntilAllTasksHaveCompleted() {
199 if (timeout_seconds_
) {
201 base::Bind(&RasterWorkerPoolTest::OnTimeout
, base::Unretained(this)));
202 base::MessageLoopProxy::current()->PostDelayedTask(
205 base::TimeDelta::FromSeconds(timeout_seconds_
));
208 base::MessageLoop::current()->Run();
212 ASSERT_FALSE(timed_out_
) << "Test timed out";
215 void ScheduleTasks() {
216 RasterTaskQueue queue
;
218 for (RasterTaskVector::const_iterator it
= tasks_
.begin();
221 TaskSetCollection task_sets
;
222 task_sets
[ALL
] = true;
223 queue
.items
.push_back(RasterTaskQueue::Item(it
->get(), task_sets
));
226 raster_worker_pool_
->AsRasterizer()->ScheduleTasks(&queue
);
229 void AppendTask(unsigned id
, const gfx::Size
& size
) {
230 scoped_ptr
<ScopedResource
> resource(
231 ScopedResource::Create(resource_provider_
.get()));
232 resource
->Allocate(size
, ResourceProvider::TextureHintImmutable
, RGBA_8888
);
233 const Resource
* const_resource
= resource
.get();
235 ImageDecodeTask::Vector empty
;
236 tasks_
.push_back(new TestRasterTaskImpl(
238 base::Bind(&RasterWorkerPoolTest::OnTaskCompleted
,
239 base::Unretained(this),
240 base::Passed(&resource
),
245 void AppendTask(unsigned id
) { AppendTask(id
, gfx::Size(1, 1)); }
247 void AppendBlockingTask(unsigned id
, base::Lock
* lock
) {
248 const gfx::Size
size(1, 1);
250 scoped_ptr
<ScopedResource
> resource(
251 ScopedResource::Create(resource_provider_
.get()));
252 resource
->Allocate(size
, ResourceProvider::TextureHintImmutable
, RGBA_8888
);
253 const Resource
* const_resource
= resource
.get();
255 ImageDecodeTask::Vector empty
;
256 tasks_
.push_back(new BlockingTestRasterTaskImpl(
258 base::Bind(&RasterWorkerPoolTest::OnTaskCompleted
,
259 base::Unretained(this),
260 base::Passed(&resource
),
266 const std::vector
<RasterTaskResult
>& completed_tasks() const {
267 return completed_tasks_
;
271 void Create3dOutputSurfaceAndResourceProvider() {
272 output_surface_
= FakeOutputSurface::Create3d(context_provider_
).Pass();
273 CHECK(output_surface_
->BindToClient(&output_surface_client_
));
274 TestWebGraphicsContext3D
* context3d
= context_provider_
->TestContext3d();
275 context3d
->set_support_sync_query(true);
276 resource_provider_
= ResourceProvider::Create(output_surface_
.get(),
278 &gpu_memory_buffer_manager_
,
285 void CreateSoftwareOutputSurfaceAndResourceProvider() {
286 output_surface_
= FakeOutputSurface::CreateSoftware(
287 make_scoped_ptr(new SoftwareOutputDevice
));
288 CHECK(output_surface_
->BindToClient(&output_surface_client_
));
289 resource_provider_
= ResourceProvider::Create(output_surface_
.get(),
290 &shared_bitmap_manager_
,
298 void OnTaskCompleted(scoped_ptr
<ScopedResource
> resource
,
300 const RasterSource::SolidColorAnalysis
& analysis
,
302 RasterTaskResult result
;
304 result
.canceled
= was_canceled
;
305 completed_tasks_
.push_back(result
);
310 base::MessageLoop::current()->Quit();
314 scoped_refptr
<TestContextProvider
> context_provider_
;
315 FakeOutputSurfaceClient output_surface_client_
;
316 scoped_ptr
<FakeOutputSurface
> output_surface_
;
317 scoped_ptr
<ResourceProvider
> resource_provider_
;
318 scoped_ptr
<ResourcePool
> staging_resource_pool_
;
319 scoped_ptr
<RasterWorkerPool
> raster_worker_pool_
;
320 TestGpuMemoryBufferManager gpu_memory_buffer_manager_
;
321 TestSharedBitmapManager shared_bitmap_manager_
;
322 base::CancelableClosure timeout_
;
323 int timeout_seconds_
;
325 RasterTaskVector tasks_
;
326 std::vector
<RasterTaskResult
> completed_tasks_
;
329 TEST_P(RasterWorkerPoolTest
, Basic
) {
334 RunMessageLoopUntilAllTasksHaveCompleted();
336 ASSERT_EQ(2u, completed_tasks().size());
337 EXPECT_FALSE(completed_tasks()[0].canceled
);
338 EXPECT_FALSE(completed_tasks()[1].canceled
);
341 TEST_P(RasterWorkerPoolTest
, FailedMapResource
) {
342 if (GetParam() == RASTER_WORKER_POOL_TYPE_BITMAP
)
345 TestWebGraphicsContext3D
* context3d
= context_provider_
->TestContext3d();
346 context3d
->set_times_map_buffer_chromium_succeeds(0);
350 RunMessageLoopUntilAllTasksHaveCompleted();
352 ASSERT_EQ(1u, completed_tasks().size());
353 EXPECT_FALSE(completed_tasks()[0].canceled
);
356 // This test checks that replacing a pending raster task with another does
357 // not prevent the DidFinishRunningTasks notification from being sent.
358 TEST_P(RasterWorkerPoolTest
, FalseThrottling
) {
361 // Schedule a task that is prevented from completing with a lock.
363 AppendBlockingTask(0u, &lock
);
366 // Schedule another task to replace the still-pending task. Because the old
367 // task is not a throttled task in the new task set, it should not prevent
368 // DidFinishRunningTasks from getting signaled.
369 RasterTaskVector tasks
;
374 // Unblock the first task to allow the second task to complete.
377 RunMessageLoopUntilAllTasksHaveCompleted();
380 TEST_P(RasterWorkerPoolTest
, LargeResources
) {
381 gfx::Size
size(kLargeResourceDimension
, kLargeResourceDimension
);
384 // Verify a resource of this size is larger than the transfer buffer.
385 scoped_ptr
<ScopedResource
> resource(
386 ScopedResource::Create(resource_provider_
.get()));
387 resource
->Allocate(size
, ResourceProvider::TextureHintImmutable
, RGBA_8888
);
388 EXPECT_GE(resource
->bytes(), kMaxTransferBufferUsageBytes
);
391 AppendTask(0u, size
);
392 AppendTask(1u, size
);
393 AppendTask(2u, size
);
396 // This will time out if a resource that is larger than the throttle limit
397 // never gets scheduled.
398 RunMessageLoopUntilAllTasksHaveCompleted();
401 INSTANTIATE_TEST_CASE_P(RasterWorkerPoolTests
,
402 RasterWorkerPoolTest
,
403 ::testing::Values(RASTER_WORKER_POOL_TYPE_PIXEL_BUFFER
,
404 RASTER_WORKER_POOL_TYPE_ZERO_COPY
,
405 RASTER_WORKER_POOL_TYPE_ONE_COPY
,
406 RASTER_WORKER_POOL_TYPE_GPU
,
407 RASTER_WORKER_POOL_TYPE_BITMAP
));