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