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.
4
5 #include "cc/resources/raster_worker_pool.h"
6
7 #include "base/time/time.h"
8 #include "cc/debug/lap_timer.h"
9 #include "cc/output/context_provider.h"
10 #include "cc/resources/direct_raster_worker_pool.h"
11 #include "cc/resources/image_copy_raster_worker_pool.h"
12 #include "cc/resources/image_raster_worker_pool.h"
13 #include "cc/resources/pixel_buffer_raster_worker_pool.h"
14 #include "cc/resources/rasterizer.h"
15 #include "cc/resources/resource_pool.h"
16 #include "cc/resources/resource_provider.h"
17 #include "cc/resources/scoped_resource.h"
18 #include "cc/test/fake_output_surface.h"
19 #include "cc/test/fake_output_surface_client.h"
20 #include "cc/test/test_context_support.h"
21 #include "cc/test/test_shared_bitmap_manager.h"
22 #include "cc/test/test_web_graphics_context_3d.h"
23 #include "testing/gtest/include/gtest/gtest.h"
24 #include "testing/perf/perf_test.h"
25 #include "third_party/khronos/GLES2/gl2.h"
26
27 namespace cc {
28 namespace {
29
30 class PerfGLES2Interface : public gpu::gles2::GLES2InterfaceStub {
31 // Overridden from gpu::gles2::GLES2Interface:
CreateImageCHROMIUM(GLsizei width,GLsizei height,GLenum internalformat,GLenum usage)32 virtual GLuint CreateImageCHROMIUM(GLsizei width,
33 GLsizei height,
34 GLenum internalformat,
35 GLenum usage) OVERRIDE {
36 return 1u;
37 }
GenBuffers(GLsizei n,GLuint * buffers)38 virtual void GenBuffers(GLsizei n, GLuint* buffers) OVERRIDE {
39 for (GLsizei i = 0; i < n; ++i)
40 buffers[i] = 1u;
41 }
GenTextures(GLsizei n,GLuint * textures)42 virtual void GenTextures(GLsizei n, GLuint* textures) OVERRIDE {
43 for (GLsizei i = 0; i < n; ++i)
44 textures[i] = 1u;
45 }
GetIntegerv(GLenum pname,GLint * params)46 virtual void GetIntegerv(GLenum pname, GLint* params) OVERRIDE {
47 if (pname == GL_MAX_TEXTURE_SIZE)
48 *params = INT_MAX;
49 }
50 };
51
52 class PerfContextProvider : public ContextProvider {
53 public:
PerfContextProvider()54 PerfContextProvider() : context_gl_(new PerfGLES2Interface) {}
55
BindToCurrentThread()56 virtual bool BindToCurrentThread() OVERRIDE { return true; }
ContextCapabilities()57 virtual Capabilities ContextCapabilities() OVERRIDE { return Capabilities(); }
ContextGL()58 virtual gpu::gles2::GLES2Interface* ContextGL() OVERRIDE {
59 return context_gl_.get();
60 }
ContextSupport()61 virtual gpu::ContextSupport* ContextSupport() OVERRIDE { return &support_; }
GrContext()62 virtual class GrContext* GrContext() OVERRIDE { return NULL; }
IsContextLost()63 virtual bool IsContextLost() OVERRIDE { return false; }
VerifyContexts()64 virtual void VerifyContexts() OVERRIDE {}
DeleteCachedResources()65 virtual void DeleteCachedResources() OVERRIDE {}
DestroyedOnMainThread()66 virtual bool DestroyedOnMainThread() OVERRIDE { return false; }
SetLostContextCallback(const LostContextCallback & cb)67 virtual void SetLostContextCallback(const LostContextCallback& cb) OVERRIDE {}
SetMemoryPolicyChangedCallback(const MemoryPolicyChangedCallback & cb)68 virtual void SetMemoryPolicyChangedCallback(
69 const MemoryPolicyChangedCallback& cb) OVERRIDE {}
70
71 private:
~PerfContextProvider()72 virtual ~PerfContextProvider() {}
73
74 scoped_ptr<PerfGLES2Interface> context_gl_;
75 TestContextSupport support_;
76 };
77
78 enum RasterWorkerPoolType {
79 RASTER_WORKER_POOL_TYPE_PIXEL_BUFFER,
80 RASTER_WORKER_POOL_TYPE_IMAGE,
81 RASTER_WORKER_POOL_TYPE_IMAGE_COPY,
82 RASTER_WORKER_POOL_TYPE_DIRECT
83 };
84
85 static const int kTimeLimitMillis = 2000;
86 static const int kWarmupRuns = 5;
87 static const int kTimeCheckInterval = 10;
88
89 class PerfImageDecodeTaskImpl : public ImageDecodeTask {
90 public:
PerfImageDecodeTaskImpl()91 PerfImageDecodeTaskImpl() {}
92
93 // Overridden from Task:
RunOnWorkerThread()94 virtual void RunOnWorkerThread() OVERRIDE {}
95
96 // Overridden from RasterizerTask:
ScheduleOnOriginThread(RasterizerTaskClient * client)97 virtual void ScheduleOnOriginThread(RasterizerTaskClient* client) OVERRIDE {}
CompleteOnOriginThread(RasterizerTaskClient * client)98 virtual void CompleteOnOriginThread(RasterizerTaskClient* client) OVERRIDE {}
RunReplyOnOriginThread()99 virtual void RunReplyOnOriginThread() OVERRIDE { Reset(); }
100
Reset()101 void Reset() {
102 did_run_ = false;
103 did_complete_ = false;
104 }
105
106 protected:
~PerfImageDecodeTaskImpl()107 virtual ~PerfImageDecodeTaskImpl() {}
108
109 private:
110 DISALLOW_COPY_AND_ASSIGN(PerfImageDecodeTaskImpl);
111 };
112
113 class PerfRasterTaskImpl : public RasterTask {
114 public:
PerfRasterTaskImpl(scoped_ptr<ScopedResource> resource,ImageDecodeTask::Vector * dependencies)115 PerfRasterTaskImpl(scoped_ptr<ScopedResource> resource,
116 ImageDecodeTask::Vector* dependencies)
117 : RasterTask(resource.get(), dependencies), resource_(resource.Pass()) {}
118
119 // Overridden from Task:
RunOnWorkerThread()120 virtual void RunOnWorkerThread() OVERRIDE {}
121
122 // Overridden from RasterizerTask:
ScheduleOnOriginThread(RasterizerTaskClient * client)123 virtual void ScheduleOnOriginThread(RasterizerTaskClient* client) OVERRIDE {
124 client->AcquireCanvasForRaster(this);
125 }
CompleteOnOriginThread(RasterizerTaskClient * client)126 virtual void CompleteOnOriginThread(RasterizerTaskClient* client) OVERRIDE {
127 client->ReleaseCanvasForRaster(this);
128 }
RunReplyOnOriginThread()129 virtual void RunReplyOnOriginThread() OVERRIDE { Reset(); }
130
Reset()131 void Reset() {
132 did_run_ = false;
133 did_complete_ = false;
134 }
135
136 protected:
~PerfRasterTaskImpl()137 virtual ~PerfRasterTaskImpl() {}
138
139 private:
140 scoped_ptr<ScopedResource> resource_;
141
142 DISALLOW_COPY_AND_ASSIGN(PerfRasterTaskImpl);
143 };
144
145 class RasterWorkerPoolPerfTestBase {
146 public:
147 typedef std::vector<scoped_refptr<RasterTask> > RasterTaskVector;
148
RasterWorkerPoolPerfTestBase()149 RasterWorkerPoolPerfTestBase()
150 : context_provider_(make_scoped_refptr(new PerfContextProvider)),
151 task_graph_runner_(new TaskGraphRunner),
152 timer_(kWarmupRuns,
153 base::TimeDelta::FromMilliseconds(kTimeLimitMillis),
154 kTimeCheckInterval) {
155 output_surface_ = FakeOutputSurface::Create3d(context_provider_).Pass();
156 CHECK(output_surface_->BindToClient(&output_surface_client_));
157
158 shared_bitmap_manager_.reset(new TestSharedBitmapManager());
159 resource_provider_ =
160 ResourceProvider::Create(
161 output_surface_.get(), shared_bitmap_manager_.get(), 0, false, 1,
162 false).Pass();
163 staging_resource_pool_ = ResourcePool::Create(
164 resource_provider_.get(), GL_TEXTURE_2D, RGBA_8888);
165 }
166
CreateImageDecodeTasks(unsigned num_image_decode_tasks,ImageDecodeTask::Vector * image_decode_tasks)167 void CreateImageDecodeTasks(unsigned num_image_decode_tasks,
168 ImageDecodeTask::Vector* image_decode_tasks) {
169 for (unsigned i = 0; i < num_image_decode_tasks; ++i)
170 image_decode_tasks->push_back(new PerfImageDecodeTaskImpl);
171 }
172
CreateRasterTasks(unsigned num_raster_tasks,const ImageDecodeTask::Vector & image_decode_tasks,RasterTaskVector * raster_tasks)173 void CreateRasterTasks(unsigned num_raster_tasks,
174 const ImageDecodeTask::Vector& image_decode_tasks,
175 RasterTaskVector* raster_tasks) {
176 const gfx::Size size(1, 1);
177
178 for (unsigned i = 0; i < num_raster_tasks; ++i) {
179 scoped_ptr<ScopedResource> resource(
180 ScopedResource::Create(resource_provider_.get()));
181 resource->Allocate(size, ResourceProvider::TextureUsageAny, RGBA_8888);
182
183 ImageDecodeTask::Vector dependencies = image_decode_tasks;
184 raster_tasks->push_back(
185 new PerfRasterTaskImpl(resource.Pass(), &dependencies));
186 }
187 }
188
BuildRasterTaskQueue(RasterTaskQueue * queue,const RasterTaskVector & raster_tasks)189 void BuildRasterTaskQueue(RasterTaskQueue* queue,
190 const RasterTaskVector& raster_tasks) {
191 for (size_t i = 0u; i < raster_tasks.size(); ++i) {
192 bool required_for_activation = (i % 2) == 0;
193 queue->items.push_back(RasterTaskQueue::Item(raster_tasks[i].get(),
194 required_for_activation));
195 queue->required_for_activation_count += required_for_activation;
196 }
197 }
198
199 protected:
200 scoped_refptr<ContextProvider> context_provider_;
201 FakeOutputSurfaceClient output_surface_client_;
202 scoped_ptr<FakeOutputSurface> output_surface_;
203 scoped_ptr<SharedBitmapManager> shared_bitmap_manager_;
204 scoped_ptr<ResourceProvider> resource_provider_;
205 scoped_ptr<ResourcePool> staging_resource_pool_;
206 scoped_ptr<TaskGraphRunner> task_graph_runner_;
207 LapTimer timer_;
208 };
209
210 class RasterWorkerPoolPerfTest
211 : public RasterWorkerPoolPerfTestBase,
212 public testing::TestWithParam<RasterWorkerPoolType>,
213 public RasterizerClient {
214 public:
RasterWorkerPoolPerfTest()215 RasterWorkerPoolPerfTest() {
216 switch (GetParam()) {
217 case RASTER_WORKER_POOL_TYPE_PIXEL_BUFFER:
218 raster_worker_pool_ = PixelBufferRasterWorkerPool::Create(
219 base::MessageLoopProxy::current().get(),
220 task_graph_runner_.get(),
221 resource_provider_.get(),
222 std::numeric_limits<size_t>::max());
223 break;
224 case RASTER_WORKER_POOL_TYPE_IMAGE:
225 raster_worker_pool_ = ImageRasterWorkerPool::Create(
226 base::MessageLoopProxy::current().get(),
227 task_graph_runner_.get(),
228 resource_provider_.get());
229 break;
230 case RASTER_WORKER_POOL_TYPE_IMAGE_COPY:
231 raster_worker_pool_ = ImageCopyRasterWorkerPool::Create(
232 base::MessageLoopProxy::current().get(),
233 task_graph_runner_.get(),
234 resource_provider_.get(),
235 staging_resource_pool_.get());
236 break;
237 case RASTER_WORKER_POOL_TYPE_DIRECT:
238 raster_worker_pool_ = DirectRasterWorkerPool::Create(
239 base::MessageLoopProxy::current().get(),
240 resource_provider_.get(),
241 context_provider_.get());
242 break;
243 }
244
245 DCHECK(raster_worker_pool_);
246 raster_worker_pool_->AsRasterizer()->SetClient(this);
247 }
248
249 // Overridden from testing::Test:
TearDown()250 virtual void TearDown() OVERRIDE {
251 raster_worker_pool_->AsRasterizer()->Shutdown();
252 raster_worker_pool_->AsRasterizer()->CheckForCompletedTasks();
253 }
254
255 // Overriden from RasterizerClient:
ShouldForceTasksRequiredForActivationToComplete() const256 virtual bool ShouldForceTasksRequiredForActivationToComplete() const
257 OVERRIDE {
258 return false;
259 }
DidFinishRunningTasks()260 virtual void DidFinishRunningTasks() OVERRIDE {
261 raster_worker_pool_->AsRasterizer()->CheckForCompletedTasks();
262 base::MessageLoop::current()->Quit();
263 }
DidFinishRunningTasksRequiredForActivation()264 virtual void DidFinishRunningTasksRequiredForActivation() OVERRIDE {}
265
RunMessageLoopUntilAllTasksHaveCompleted()266 void RunMessageLoopUntilAllTasksHaveCompleted() {
267 task_graph_runner_->RunUntilIdle();
268 base::MessageLoop::current()->Run();
269 }
270
RunScheduleTasksTest(const std::string & test_name,unsigned num_raster_tasks,unsigned num_image_decode_tasks)271 void RunScheduleTasksTest(const std::string& test_name,
272 unsigned num_raster_tasks,
273 unsigned num_image_decode_tasks) {
274 ImageDecodeTask::Vector image_decode_tasks;
275 RasterTaskVector raster_tasks;
276 CreateImageDecodeTasks(num_image_decode_tasks, &image_decode_tasks);
277 CreateRasterTasks(num_raster_tasks, image_decode_tasks, &raster_tasks);
278
279 // Avoid unnecessary heap allocations by reusing the same queue.
280 RasterTaskQueue queue;
281
282 timer_.Reset();
283 do {
284 queue.Reset();
285 BuildRasterTaskQueue(&queue, raster_tasks);
286 raster_worker_pool_->AsRasterizer()->ScheduleTasks(&queue);
287 raster_worker_pool_->AsRasterizer()->CheckForCompletedTasks();
288 timer_.NextLap();
289 } while (!timer_.HasTimeLimitExpired());
290
291 RasterTaskQueue empty;
292 raster_worker_pool_->AsRasterizer()->ScheduleTasks(&empty);
293 RunMessageLoopUntilAllTasksHaveCompleted();
294
295 perf_test::PrintResult("schedule_tasks",
296 TestModifierString(),
297 test_name,
298 timer_.LapsPerSecond(),
299 "runs/s",
300 true);
301 }
302
RunScheduleAlternateTasksTest(const std::string & test_name,unsigned num_raster_tasks,unsigned num_image_decode_tasks)303 void RunScheduleAlternateTasksTest(const std::string& test_name,
304 unsigned num_raster_tasks,
305 unsigned num_image_decode_tasks) {
306 const size_t kNumVersions = 2;
307 ImageDecodeTask::Vector image_decode_tasks[kNumVersions];
308 RasterTaskVector raster_tasks[kNumVersions];
309 for (size_t i = 0; i < kNumVersions; ++i) {
310 CreateImageDecodeTasks(num_image_decode_tasks, &image_decode_tasks[i]);
311 CreateRasterTasks(
312 num_raster_tasks, image_decode_tasks[i], &raster_tasks[i]);
313 }
314
315 // Avoid unnecessary heap allocations by reusing the same queue.
316 RasterTaskQueue queue;
317
318 size_t count = 0;
319 timer_.Reset();
320 do {
321 queue.Reset();
322 BuildRasterTaskQueue(&queue, raster_tasks[count % kNumVersions]);
323 raster_worker_pool_->AsRasterizer()->ScheduleTasks(&queue);
324 raster_worker_pool_->AsRasterizer()->CheckForCompletedTasks();
325 ++count;
326 timer_.NextLap();
327 } while (!timer_.HasTimeLimitExpired());
328
329 RasterTaskQueue empty;
330 raster_worker_pool_->AsRasterizer()->ScheduleTasks(&empty);
331 RunMessageLoopUntilAllTasksHaveCompleted();
332
333 perf_test::PrintResult("schedule_alternate_tasks",
334 TestModifierString(),
335 test_name,
336 timer_.LapsPerSecond(),
337 "runs/s",
338 true);
339 }
340
RunScheduleAndExecuteTasksTest(const std::string & test_name,unsigned num_raster_tasks,unsigned num_image_decode_tasks)341 void RunScheduleAndExecuteTasksTest(const std::string& test_name,
342 unsigned num_raster_tasks,
343 unsigned num_image_decode_tasks) {
344 ImageDecodeTask::Vector image_decode_tasks;
345 RasterTaskVector raster_tasks;
346 CreateImageDecodeTasks(num_image_decode_tasks, &image_decode_tasks);
347 CreateRasterTasks(num_raster_tasks, image_decode_tasks, &raster_tasks);
348
349 // Avoid unnecessary heap allocations by reusing the same queue.
350 RasterTaskQueue queue;
351
352 timer_.Reset();
353 do {
354 queue.Reset();
355 BuildRasterTaskQueue(&queue, raster_tasks);
356 raster_worker_pool_->AsRasterizer()->ScheduleTasks(&queue);
357 RunMessageLoopUntilAllTasksHaveCompleted();
358 timer_.NextLap();
359 } while (!timer_.HasTimeLimitExpired());
360
361 RasterTaskQueue empty;
362 raster_worker_pool_->AsRasterizer()->ScheduleTasks(&empty);
363 RunMessageLoopUntilAllTasksHaveCompleted();
364
365 perf_test::PrintResult("schedule_and_execute_tasks",
366 TestModifierString(),
367 test_name,
368 timer_.LapsPerSecond(),
369 "runs/s",
370 true);
371 }
372
373 private:
TestModifierString() const374 std::string TestModifierString() const {
375 switch (GetParam()) {
376 case RASTER_WORKER_POOL_TYPE_PIXEL_BUFFER:
377 return std::string("_pixel_raster_worker_pool");
378 case RASTER_WORKER_POOL_TYPE_IMAGE:
379 return std::string("_image_raster_worker_pool");
380 case RASTER_WORKER_POOL_TYPE_IMAGE_COPY:
381 return std::string("_image_copy_raster_worker_pool");
382 case RASTER_WORKER_POOL_TYPE_DIRECT:
383 return std::string("_direct_raster_worker_pool");
384 }
385 NOTREACHED();
386 return std::string();
387 }
388
389 scoped_ptr<RasterWorkerPool> raster_worker_pool_;
390 };
391
TEST_P(RasterWorkerPoolPerfTest,ScheduleTasks)392 TEST_P(RasterWorkerPoolPerfTest, ScheduleTasks) {
393 RunScheduleTasksTest("1_0", 1, 0);
394 RunScheduleTasksTest("32_0", 32, 0);
395 RunScheduleTasksTest("1_1", 1, 1);
396 RunScheduleTasksTest("32_1", 32, 1);
397 RunScheduleTasksTest("1_4", 1, 4);
398 RunScheduleTasksTest("32_4", 32, 4);
399 }
400
TEST_P(RasterWorkerPoolPerfTest,ScheduleAlternateTasks)401 TEST_P(RasterWorkerPoolPerfTest, ScheduleAlternateTasks) {
402 RunScheduleAlternateTasksTest("1_0", 1, 0);
403 RunScheduleAlternateTasksTest("32_0", 32, 0);
404 RunScheduleAlternateTasksTest("1_1", 1, 1);
405 RunScheduleAlternateTasksTest("32_1", 32, 1);
406 RunScheduleAlternateTasksTest("1_4", 1, 4);
407 RunScheduleAlternateTasksTest("32_4", 32, 4);
408 }
409
TEST_P(RasterWorkerPoolPerfTest,ScheduleAndExecuteTasks)410 TEST_P(RasterWorkerPoolPerfTest, ScheduleAndExecuteTasks) {
411 RunScheduleAndExecuteTasksTest("1_0", 1, 0);
412 RunScheduleAndExecuteTasksTest("32_0", 32, 0);
413 RunScheduleAndExecuteTasksTest("1_1", 1, 1);
414 RunScheduleAndExecuteTasksTest("32_1", 32, 1);
415 RunScheduleAndExecuteTasksTest("1_4", 1, 4);
416 RunScheduleAndExecuteTasksTest("32_4", 32, 4);
417 }
418
419 INSTANTIATE_TEST_CASE_P(RasterWorkerPoolPerfTests,
420 RasterWorkerPoolPerfTest,
421 ::testing::Values(RASTER_WORKER_POOL_TYPE_PIXEL_BUFFER,
422 RASTER_WORKER_POOL_TYPE_IMAGE,
423 RASTER_WORKER_POOL_TYPE_IMAGE_COPY,
424 RASTER_WORKER_POOL_TYPE_DIRECT));
425
426 class RasterWorkerPoolCommonPerfTest : public RasterWorkerPoolPerfTestBase,
427 public testing::Test {
428 public:
RunBuildRasterTaskQueueTest(const std::string & test_name,unsigned num_raster_tasks,unsigned num_image_decode_tasks)429 void RunBuildRasterTaskQueueTest(const std::string& test_name,
430 unsigned num_raster_tasks,
431 unsigned num_image_decode_tasks) {
432 ImageDecodeTask::Vector image_decode_tasks;
433 RasterTaskVector raster_tasks;
434 CreateImageDecodeTasks(num_image_decode_tasks, &image_decode_tasks);
435 CreateRasterTasks(num_raster_tasks, image_decode_tasks, &raster_tasks);
436
437 // Avoid unnecessary heap allocations by reusing the same queue.
438 RasterTaskQueue queue;
439
440 timer_.Reset();
441 do {
442 queue.Reset();
443 BuildRasterTaskQueue(&queue, raster_tasks);
444 timer_.NextLap();
445 } while (!timer_.HasTimeLimitExpired());
446
447 perf_test::PrintResult("build_raster_task_queue",
448 "",
449 test_name,
450 timer_.LapsPerSecond(),
451 "runs/s",
452 true);
453 }
454 };
455
TEST_F(RasterWorkerPoolCommonPerfTest,BuildRasterTaskQueue)456 TEST_F(RasterWorkerPoolCommonPerfTest, BuildRasterTaskQueue) {
457 RunBuildRasterTaskQueueTest("1_0", 1, 0);
458 RunBuildRasterTaskQueueTest("32_0", 32, 0);
459 RunBuildRasterTaskQueueTest("1_1", 1, 1);
460 RunBuildRasterTaskQueueTest("32_1", 32, 1);
461 RunBuildRasterTaskQueueTest("1_4", 1, 4);
462 RunBuildRasterTaskQueueTest("32_4", 32, 4);
463 }
464
465 } // namespace
466 } // namespace cc
467