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/gpu_raster_worker_pool.h"
12 #include "cc/resources/image_copy_raster_worker_pool.h"
13 #include "cc/resources/image_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/rasterizer.h"
18 #include "cc/resources/resource_pool.h"
19 #include "cc/resources/resource_provider.h"
20 #include "cc/resources/scoped_resource.h"
21 #include "cc/test/fake_output_surface.h"
22 #include "cc/test/fake_output_surface_client.h"
23 #include "cc/test/test_shared_bitmap_manager.h"
24 #include "cc/test/test_web_graphics_context_3d.h"
25 #include "testing/gtest/include/gtest/gtest.h"
30 const size_t kMaxTransferBufferUsageBytes = 10000U;
31 // A resource of this dimension^2 * 4 must be greater than the above transfer
33 const size_t kLargeResourceDimension = 1000U;
35 enum RasterWorkerPoolType {
36 RASTER_WORKER_POOL_TYPE_PIXEL_BUFFER,
37 RASTER_WORKER_POOL_TYPE_IMAGE,
38 RASTER_WORKER_POOL_TYPE_IMAGE_COPY,
39 RASTER_WORKER_POOL_TYPE_GPU
42 class TestRasterTaskImpl : public RasterTask {
44 typedef base::Callback<
45 void(const PicturePileImpl::Analysis& analysis, bool was_canceled)> Reply;
47 TestRasterTaskImpl(const Resource* resource,
49 ImageDecodeTask::Vector* dependencies)
50 : RasterTask(resource, dependencies), reply_(reply) {}
52 // Overridden from Task:
53 virtual void RunOnWorkerThread() OVERRIDE {}
55 // Overridden from RasterizerTask:
56 virtual void ScheduleOnOriginThread(RasterizerTaskClient* client) OVERRIDE {
57 client->AcquireCanvasForRaster(this);
59 virtual void CompleteOnOriginThread(RasterizerTaskClient* client) OVERRIDE {
60 client->ReleaseCanvasForRaster(this);
62 virtual void RunReplyOnOriginThread() OVERRIDE {
63 reply_.Run(PicturePileImpl::Analysis(), !HasFinishedRunning());
67 virtual ~TestRasterTaskImpl() {}
72 DISALLOW_COPY_AND_ASSIGN(TestRasterTaskImpl);
75 class BlockingTestRasterTaskImpl : public TestRasterTaskImpl {
77 BlockingTestRasterTaskImpl(const Resource* resource,
80 ImageDecodeTask::Vector* dependencies)
81 : TestRasterTaskImpl(resource, reply, dependencies), lock_(lock) {}
83 // Overridden from Task:
84 virtual void RunOnWorkerThread() OVERRIDE {
85 base::AutoLock lock(*lock_);
86 TestRasterTaskImpl::RunOnWorkerThread();
89 // Overridden from RasterizerTask:
90 virtual void RunReplyOnOriginThread() OVERRIDE {}
93 virtual ~BlockingTestRasterTaskImpl() {}
98 DISALLOW_COPY_AND_ASSIGN(BlockingTestRasterTaskImpl);
101 class RasterWorkerPoolTest
102 : public testing::TestWithParam<RasterWorkerPoolType>,
103 public RasterizerClient {
105 struct RasterTaskResult {
110 typedef std::vector<scoped_refptr<RasterTask> > RasterTaskVector;
112 RasterWorkerPoolTest()
113 : context_provider_(TestContextProvider::Create()),
116 output_surface_ = FakeOutputSurface::Create3d(context_provider_).Pass();
117 CHECK(output_surface_->BindToClient(&output_surface_client_));
119 shared_bitmap_manager_.reset(new TestSharedBitmapManager());
121 ResourceProvider::Create(
122 output_surface_.get(), shared_bitmap_manager_.get(), 0, false, 1,
124 staging_resource_pool_ = ResourcePool::Create(
125 resource_provider_.get(), GL_TEXTURE_2D, RGBA_8888);
127 switch (GetParam()) {
128 case RASTER_WORKER_POOL_TYPE_PIXEL_BUFFER:
129 raster_worker_pool_ = PixelBufferRasterWorkerPool::Create(
130 base::MessageLoopProxy::current().get(),
131 RasterWorkerPool::GetTaskGraphRunner(),
132 context_provider_.get(),
133 resource_provider_.get(),
134 kMaxTransferBufferUsageBytes);
136 case RASTER_WORKER_POOL_TYPE_IMAGE:
137 raster_worker_pool_ = ImageRasterWorkerPool::Create(
138 base::MessageLoopProxy::current().get(),
139 RasterWorkerPool::GetTaskGraphRunner(),
140 resource_provider_.get());
142 case RASTER_WORKER_POOL_TYPE_IMAGE_COPY:
143 raster_worker_pool_ = ImageCopyRasterWorkerPool::Create(
144 base::MessageLoopProxy::current().get(),
145 RasterWorkerPool::GetTaskGraphRunner(),
146 context_provider_.get(),
147 resource_provider_.get(),
148 staging_resource_pool_.get());
150 case RASTER_WORKER_POOL_TYPE_GPU:
151 raster_worker_pool_ =
152 GpuRasterWorkerPool::Create(base::MessageLoopProxy::current().get(),
153 context_provider_.get(),
154 resource_provider_.get());
158 DCHECK(raster_worker_pool_);
159 raster_worker_pool_->AsRasterizer()->SetClient(this);
161 virtual ~RasterWorkerPoolTest() {
162 staging_resource_pool_.reset();
163 resource_provider_.reset();
166 // Overridden from testing::Test:
167 virtual void TearDown() OVERRIDE {
168 raster_worker_pool_->AsRasterizer()->Shutdown();
169 raster_worker_pool_->AsRasterizer()->CheckForCompletedTasks();
172 // Overriden from RasterWorkerPoolClient:
173 virtual bool ShouldForceTasksRequiredForActivationToComplete() const
177 virtual void DidFinishRunningTasks() OVERRIDE {
178 raster_worker_pool_->AsRasterizer()->CheckForCompletedTasks();
179 base::MessageLoop::current()->Quit();
181 virtual void DidFinishRunningTasksRequiredForActivation() OVERRIDE {}
183 void RunMessageLoopUntilAllTasksHaveCompleted() {
184 if (timeout_seconds_) {
186 base::Bind(&RasterWorkerPoolTest::OnTimeout, base::Unretained(this)));
187 base::MessageLoopProxy::current()->PostDelayedTask(
190 base::TimeDelta::FromSeconds(timeout_seconds_));
193 base::MessageLoop::current()->Run();
197 ASSERT_FALSE(timed_out_) << "Test timed out";
200 void ScheduleTasks() {
201 RasterTaskQueue queue;
203 for (RasterTaskVector::const_iterator it = tasks_.begin();
206 queue.items.push_back(RasterTaskQueue::Item(*it, false));
208 raster_worker_pool_->AsRasterizer()->ScheduleTasks(&queue);
211 void AppendTask(unsigned id, const gfx::Size& size) {
212 scoped_ptr<ScopedResource> resource(
213 ScopedResource::Create(resource_provider_.get()));
214 resource->Allocate(size, ResourceProvider::TextureUsageAny, RGBA_8888);
215 const Resource* const_resource = resource.get();
217 ImageDecodeTask::Vector empty;
218 tasks_.push_back(new TestRasterTaskImpl(
220 base::Bind(&RasterWorkerPoolTest::OnTaskCompleted,
221 base::Unretained(this),
222 base::Passed(&resource),
227 void AppendTask(unsigned id) { AppendTask(id, gfx::Size(1, 1)); }
229 void AppendBlockingTask(unsigned id, base::Lock* lock) {
230 const gfx::Size size(1, 1);
232 scoped_ptr<ScopedResource> resource(
233 ScopedResource::Create(resource_provider_.get()));
234 resource->Allocate(size, ResourceProvider::TextureUsageAny, RGBA_8888);
235 const Resource* const_resource = resource.get();
237 ImageDecodeTask::Vector empty;
238 tasks_.push_back(new BlockingTestRasterTaskImpl(
240 base::Bind(&RasterWorkerPoolTest::OnTaskCompleted,
241 base::Unretained(this),
242 base::Passed(&resource),
248 const std::vector<RasterTaskResult>& completed_tasks() const {
249 return completed_tasks_;
253 void OnTaskCompleted(scoped_ptr<ScopedResource> resource,
255 const PicturePileImpl::Analysis& analysis,
257 RasterTaskResult result;
259 result.canceled = was_canceled;
260 completed_tasks_.push_back(result);
265 base::MessageLoop::current()->Quit();
269 scoped_refptr<TestContextProvider> context_provider_;
270 FakeOutputSurfaceClient output_surface_client_;
271 scoped_ptr<FakeOutputSurface> output_surface_;
272 scoped_ptr<SharedBitmapManager> shared_bitmap_manager_;
273 scoped_ptr<ResourceProvider> resource_provider_;
274 scoped_ptr<ResourcePool> staging_resource_pool_;
275 scoped_ptr<RasterWorkerPool> raster_worker_pool_;
276 base::CancelableClosure timeout_;
277 int timeout_seconds_;
279 RasterTaskVector tasks_;
280 std::vector<RasterTaskResult> completed_tasks_;
283 TEST_P(RasterWorkerPoolTest, Basic) {
288 RunMessageLoopUntilAllTasksHaveCompleted();
290 ASSERT_EQ(2u, completed_tasks().size());
291 EXPECT_FALSE(completed_tasks()[0].canceled);
292 EXPECT_FALSE(completed_tasks()[1].canceled);
295 TEST_P(RasterWorkerPoolTest, FailedMapResource) {
296 TestWebGraphicsContext3D* context3d = context_provider_->TestContext3d();
297 context3d->set_times_map_image_chromium_succeeds(0);
298 context3d->set_times_map_buffer_chromium_succeeds(0);
302 RunMessageLoopUntilAllTasksHaveCompleted();
304 ASSERT_EQ(1u, completed_tasks().size());
305 EXPECT_FALSE(completed_tasks()[0].canceled);
308 // This test checks that replacing a pending raster task with another does
309 // not prevent the DidFinishRunningTasks notification from being sent.
310 TEST_P(RasterWorkerPoolTest, FalseThrottling) {
313 // Schedule a task that is prevented from completing with a lock.
315 AppendBlockingTask(0u, &lock);
318 // Schedule another task to replace the still-pending task. Because the old
319 // task is not a throttled task in the new task set, it should not prevent
320 // DidFinishRunningTasks from getting signaled.
321 RasterTaskVector tasks;
326 // Unblock the first task to allow the second task to complete.
329 RunMessageLoopUntilAllTasksHaveCompleted();
332 TEST_P(RasterWorkerPoolTest, LargeResources) {
333 gfx::Size size(kLargeResourceDimension, kLargeResourceDimension);
336 // Verify a resource of this size is larger than the transfer buffer.
337 scoped_ptr<ScopedResource> resource(
338 ScopedResource::Create(resource_provider_.get()));
339 resource->Allocate(size, ResourceProvider::TextureUsageAny, RGBA_8888);
340 EXPECT_GE(resource->bytes(), kMaxTransferBufferUsageBytes);
343 AppendTask(0u, size);
344 AppendTask(1u, size);
345 AppendTask(2u, size);
348 // This will time out if a resource that is larger than the throttle limit
349 // never gets scheduled.
350 RunMessageLoopUntilAllTasksHaveCompleted();
353 INSTANTIATE_TEST_CASE_P(RasterWorkerPoolTests,
354 RasterWorkerPoolTest,
355 ::testing::Values(RASTER_WORKER_POOL_TYPE_PIXEL_BUFFER,
356 RASTER_WORKER_POOL_TYPE_IMAGE,
357 RASTER_WORKER_POOL_TYPE_IMAGE_COPY,
358 RASTER_WORKER_POOL_TYPE_GPU));