OLD | NEW |
| (Empty) |
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 <stddef.h> | |
6 #include <stdint.h> | |
7 | |
8 #include "base/macros.h" | |
9 #include "base/memory/ptr_util.h" | |
10 #include "base/test/test_simple_task_runner.h" | |
11 #include "base/time/time.h" | |
12 #include "cc/debug/lap_timer.h" | |
13 #include "cc/output/context_provider.h" | |
14 #include "cc/raster/bitmap_tile_task_worker_pool.h" | |
15 #include "cc/raster/gpu_rasterizer.h" | |
16 #include "cc/raster/gpu_tile_task_worker_pool.h" | |
17 #include "cc/raster/one_copy_tile_task_worker_pool.h" | |
18 #include "cc/raster/synchronous_task_graph_runner.h" | |
19 #include "cc/raster/tile_task_worker_pool.h" | |
20 #include "cc/raster/zero_copy_tile_task_worker_pool.h" | |
21 #include "cc/resources/resource_pool.h" | |
22 #include "cc/resources/resource_provider.h" | |
23 #include "cc/resources/scoped_resource.h" | |
24 #include "cc/test/fake_output_surface.h" | |
25 #include "cc/test/fake_output_surface_client.h" | |
26 #include "cc/test/fake_resource_provider.h" | |
27 #include "cc/test/test_context_support.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_web_graphics_context_3d.h" | |
31 #include "testing/gtest/include/gtest/gtest.h" | |
32 #include "testing/perf/perf_test.h" | |
33 #include "third_party/khronos/GLES2/gl2.h" | |
34 #include "third_party/skia/include/gpu/GrContext.h" | |
35 #include "third_party/skia/include/gpu/gl/GrGLInterface.h" | |
36 | |
37 namespace cc { | |
38 namespace { | |
39 | |
40 class PerfGLES2Interface : public gpu::gles2::GLES2InterfaceStub { | |
41 // Overridden from gpu::gles2::GLES2Interface: | |
42 GLuint CreateImageCHROMIUM(ClientBuffer buffer, | |
43 GLsizei width, | |
44 GLsizei height, | |
45 GLenum internalformat) override { | |
46 return 1u; | |
47 } | |
48 void GenBuffers(GLsizei n, GLuint* buffers) override { | |
49 for (GLsizei i = 0; i < n; ++i) | |
50 buffers[i] = 1u; | |
51 } | |
52 void GenTextures(GLsizei n, GLuint* textures) override { | |
53 for (GLsizei i = 0; i < n; ++i) | |
54 textures[i] = 1u; | |
55 } | |
56 void GetIntegerv(GLenum pname, GLint* params) override { | |
57 if (pname == GL_MAX_TEXTURE_SIZE) | |
58 *params = INT_MAX; | |
59 } | |
60 void GenQueriesEXT(GLsizei n, GLuint* queries) override { | |
61 for (GLsizei i = 0; i < n; ++i) | |
62 queries[i] = 1u; | |
63 } | |
64 void GetQueryObjectuivEXT(GLuint query, | |
65 GLenum pname, | |
66 GLuint* params) override { | |
67 if (pname == GL_QUERY_RESULT_AVAILABLE_EXT) | |
68 *params = 1; | |
69 } | |
70 }; | |
71 | |
72 class PerfContextProvider : public ContextProvider { | |
73 public: | |
74 PerfContextProvider() : context_gl_(new PerfGLES2Interface) {} | |
75 | |
76 bool BindToCurrentThread() override { return true; } | |
77 Capabilities ContextCapabilities() override { | |
78 Capabilities capabilities; | |
79 capabilities.gpu.image = true; | |
80 capabilities.gpu.sync_query = true; | |
81 return capabilities; | |
82 } | |
83 gpu::gles2::GLES2Interface* ContextGL() override { return context_gl_.get(); } | |
84 gpu::ContextSupport* ContextSupport() override { return &support_; } | |
85 class GrContext* GrContext() override { | |
86 if (gr_context_) | |
87 return gr_context_.get(); | |
88 | |
89 skia::RefPtr<const GrGLInterface> null_interface = | |
90 skia::AdoptRef(GrGLCreateNullInterface()); | |
91 gr_context_ = skia::AdoptRef(GrContext::Create( | |
92 kOpenGL_GrBackend, | |
93 reinterpret_cast<GrBackendContext>(null_interface.get()))); | |
94 return gr_context_.get(); | |
95 } | |
96 void InvalidateGrContext(uint32_t state) override { | |
97 if (gr_context_) | |
98 gr_context_.get()->resetContext(state); | |
99 } | |
100 void SetupLock() override {} | |
101 base::Lock* GetLock() override { return &context_lock_; } | |
102 void DeleteCachedResources() override {} | |
103 void SetLostContextCallback(const LostContextCallback& cb) override {} | |
104 | |
105 private: | |
106 ~PerfContextProvider() override {} | |
107 | |
108 std::unique_ptr<PerfGLES2Interface> context_gl_; | |
109 skia::RefPtr<class GrContext> gr_context_; | |
110 TestContextSupport support_; | |
111 base::Lock context_lock_; | |
112 }; | |
113 | |
114 enum TileTaskWorkerPoolType { | |
115 TILE_TASK_WORKER_POOL_TYPE_ZERO_COPY, | |
116 TILE_TASK_WORKER_POOL_TYPE_ONE_COPY, | |
117 TILE_TASK_WORKER_POOL_TYPE_GPU, | |
118 TILE_TASK_WORKER_POOL_TYPE_BITMAP | |
119 }; | |
120 | |
121 static const int kTimeLimitMillis = 2000; | |
122 static const int kWarmupRuns = 5; | |
123 static const int kTimeCheckInterval = 10; | |
124 | |
125 class PerfImageDecodeTaskImpl : public TileTask { | |
126 public: | |
127 PerfImageDecodeTaskImpl() : TileTask(true) {} | |
128 | |
129 // Overridden from Task: | |
130 void RunOnWorkerThread() override {} | |
131 | |
132 // Overridden from TileTask: | |
133 void ScheduleOnOriginThread(RasterBufferProvider* provider) override {} | |
134 void CompleteOnOriginThread(RasterBufferProvider* provider) override { | |
135 Reset(); | |
136 } | |
137 | |
138 void Reset() { | |
139 state().Reset(); | |
140 did_complete_ = false; | |
141 } | |
142 | |
143 protected: | |
144 ~PerfImageDecodeTaskImpl() override {} | |
145 | |
146 private: | |
147 DISALLOW_COPY_AND_ASSIGN(PerfImageDecodeTaskImpl); | |
148 }; | |
149 | |
150 class PerfRasterTaskImpl : public TileTask { | |
151 public: | |
152 PerfRasterTaskImpl(std::unique_ptr<ScopedResource> resource, | |
153 TileTask::Vector* dependencies) | |
154 : TileTask(true, dependencies), resource_(std::move(resource)) {} | |
155 | |
156 // Overridden from Task: | |
157 void RunOnWorkerThread() override {} | |
158 | |
159 // Overridden from TileTask: | |
160 void ScheduleOnOriginThread(RasterBufferProvider* provider) override { | |
161 // No tile ids are given to support partial updates. | |
162 raster_buffer_ = provider->AcquireBufferForRaster(resource_.get(), 0, 0); | |
163 } | |
164 void CompleteOnOriginThread(RasterBufferProvider* provider) override { | |
165 provider->ReleaseBufferForRaster(std::move(raster_buffer_)); | |
166 Reset(); | |
167 } | |
168 | |
169 void Reset() { | |
170 state().Reset(); | |
171 did_complete_ = false; | |
172 } | |
173 | |
174 protected: | |
175 ~PerfRasterTaskImpl() override {} | |
176 | |
177 private: | |
178 std::unique_ptr<ScopedResource> resource_; | |
179 std::unique_ptr<RasterBuffer> raster_buffer_; | |
180 | |
181 DISALLOW_COPY_AND_ASSIGN(PerfRasterTaskImpl); | |
182 }; | |
183 | |
184 class TileTaskWorkerPoolPerfTestBase { | |
185 public: | |
186 typedef std::vector<scoped_refptr<TileTask>> RasterTaskVector; | |
187 | |
188 enum NamedTaskSet { REQUIRED_FOR_ACTIVATION, REQUIRED_FOR_DRAW, ALL }; | |
189 | |
190 TileTaskWorkerPoolPerfTestBase() | |
191 : context_provider_(make_scoped_refptr(new PerfContextProvider)), | |
192 task_runner_(new base::TestSimpleTaskRunner), | |
193 task_graph_runner_(new SynchronousTaskGraphRunner), | |
194 timer_(kWarmupRuns, | |
195 base::TimeDelta::FromMilliseconds(kTimeLimitMillis), | |
196 kTimeCheckInterval) {} | |
197 | |
198 void CreateImageDecodeTasks(unsigned num_image_decode_tasks, | |
199 TileTask::Vector* image_decode_tasks) { | |
200 for (unsigned i = 0; i < num_image_decode_tasks; ++i) | |
201 image_decode_tasks->push_back(new PerfImageDecodeTaskImpl); | |
202 } | |
203 | |
204 void CreateRasterTasks(unsigned num_raster_tasks, | |
205 unsigned num_image_decode_tasks, | |
206 RasterTaskVector* raster_tasks) { | |
207 const gfx::Size size(1, 1); | |
208 | |
209 for (unsigned i = 0; i < num_raster_tasks; ++i) { | |
210 TileTask::Vector image_decode_tasks; | |
211 CreateImageDecodeTasks(num_image_decode_tasks, &image_decode_tasks); | |
212 std::unique_ptr<ScopedResource> resource( | |
213 ScopedResource::Create(resource_provider_.get())); | |
214 resource->Allocate(size, ResourceProvider::TEXTURE_HINT_IMMUTABLE, | |
215 RGBA_8888); | |
216 | |
217 raster_tasks->push_back( | |
218 new PerfRasterTaskImpl(std::move(resource), &image_decode_tasks)); | |
219 } | |
220 } | |
221 | |
222 void BuildTileTaskGraph(TaskGraph* graph, | |
223 const RasterTaskVector& raster_tasks) { | |
224 uint16_t priority = 0; | |
225 | |
226 for (auto& raster_task : raster_tasks) { | |
227 priority++; | |
228 | |
229 for (auto& decode_task : raster_task->dependencies()) { | |
230 graph->nodes.push_back( | |
231 TaskGraph::Node(decode_task.get(), 0u /* group */, priority, 0u)); | |
232 graph->edges.push_back( | |
233 TaskGraph::Edge(raster_task.get(), decode_task.get())); | |
234 } | |
235 | |
236 graph->nodes.push_back(TaskGraph::Node( | |
237 raster_task.get(), 0u /* group */, priority, | |
238 static_cast<uint32_t>(raster_task->dependencies().size()))); | |
239 } | |
240 } | |
241 | |
242 protected: | |
243 scoped_refptr<ContextProvider> context_provider_; | |
244 FakeOutputSurfaceClient output_surface_client_; | |
245 std::unique_ptr<FakeOutputSurface> output_surface_; | |
246 std::unique_ptr<ResourceProvider> resource_provider_; | |
247 scoped_refptr<base::TestSimpleTaskRunner> task_runner_; | |
248 std::unique_ptr<SynchronousTaskGraphRunner> task_graph_runner_; | |
249 LapTimer timer_; | |
250 }; | |
251 | |
252 class TileTaskWorkerPoolPerfTest | |
253 : public TileTaskWorkerPoolPerfTestBase, | |
254 public testing::TestWithParam<TileTaskWorkerPoolType> { | |
255 public: | |
256 // Overridden from testing::Test: | |
257 void SetUp() override { | |
258 switch (GetParam()) { | |
259 case TILE_TASK_WORKER_POOL_TYPE_ZERO_COPY: | |
260 Create3dOutputSurfaceAndResourceProvider(); | |
261 tile_task_worker_pool_ = ZeroCopyTileTaskWorkerPool::Create( | |
262 task_runner_.get(), task_graph_runner_.get(), | |
263 resource_provider_.get(), PlatformColor::BestTextureFormat()); | |
264 break; | |
265 case TILE_TASK_WORKER_POOL_TYPE_ONE_COPY: | |
266 Create3dOutputSurfaceAndResourceProvider(); | |
267 tile_task_worker_pool_ = OneCopyTileTaskWorkerPool::Create( | |
268 task_runner_.get(), task_graph_runner_.get(), | |
269 context_provider_.get(), resource_provider_.get(), | |
270 std::numeric_limits<int>::max(), false, | |
271 std::numeric_limits<int>::max(), | |
272 PlatformColor::BestTextureFormat()); | |
273 break; | |
274 case TILE_TASK_WORKER_POOL_TYPE_GPU: | |
275 Create3dOutputSurfaceAndResourceProvider(); | |
276 tile_task_worker_pool_ = GpuTileTaskWorkerPool::Create( | |
277 task_runner_.get(), task_graph_runner_.get(), | |
278 context_provider_.get(), resource_provider_.get(), false, 0); | |
279 break; | |
280 case TILE_TASK_WORKER_POOL_TYPE_BITMAP: | |
281 CreateSoftwareOutputSurfaceAndResourceProvider(); | |
282 tile_task_worker_pool_ = BitmapTileTaskWorkerPool::Create( | |
283 task_runner_.get(), task_graph_runner_.get(), | |
284 resource_provider_.get()); | |
285 break; | |
286 } | |
287 | |
288 DCHECK(tile_task_worker_pool_); | |
289 } | |
290 void TearDown() override { | |
291 tile_task_worker_pool_->Shutdown(); | |
292 tile_task_worker_pool_->CheckForCompletedTasks(); | |
293 } | |
294 | |
295 void RunMessageLoopUntilAllTasksHaveCompleted() { | |
296 task_graph_runner_->RunUntilIdle(); | |
297 task_runner_->RunUntilIdle(); | |
298 } | |
299 | |
300 void RunScheduleTasksTest(const std::string& test_name, | |
301 unsigned num_raster_tasks, | |
302 unsigned num_image_decode_tasks) { | |
303 RasterTaskVector raster_tasks; | |
304 CreateRasterTasks(num_raster_tasks, num_image_decode_tasks, &raster_tasks); | |
305 | |
306 // Avoid unnecessary heap allocations by reusing the same graph. | |
307 TaskGraph graph; | |
308 | |
309 timer_.Reset(); | |
310 do { | |
311 graph.Reset(); | |
312 BuildTileTaskGraph(&graph, raster_tasks); | |
313 tile_task_worker_pool_->ScheduleTasks(&graph); | |
314 tile_task_worker_pool_->CheckForCompletedTasks(); | |
315 timer_.NextLap(); | |
316 } while (!timer_.HasTimeLimitExpired()); | |
317 | |
318 TaskGraph empty; | |
319 tile_task_worker_pool_->ScheduleTasks(&empty); | |
320 RunMessageLoopUntilAllTasksHaveCompleted(); | |
321 | |
322 perf_test::PrintResult("schedule_tasks", TestModifierString(), test_name, | |
323 timer_.LapsPerSecond(), "runs/s", true); | |
324 } | |
325 | |
326 void RunScheduleAlternateTasksTest(const std::string& test_name, | |
327 unsigned num_raster_tasks, | |
328 unsigned num_image_decode_tasks) { | |
329 const size_t kNumVersions = 2; | |
330 RasterTaskVector raster_tasks[kNumVersions]; | |
331 for (size_t i = 0; i < kNumVersions; ++i) { | |
332 CreateRasterTasks(num_raster_tasks, num_image_decode_tasks, | |
333 &raster_tasks[i]); | |
334 } | |
335 | |
336 // Avoid unnecessary heap allocations by reusing the same graph. | |
337 TaskGraph graph; | |
338 | |
339 size_t count = 0; | |
340 timer_.Reset(); | |
341 do { | |
342 graph.Reset(); | |
343 BuildTileTaskGraph(&graph, raster_tasks[count % kNumVersions]); | |
344 tile_task_worker_pool_->ScheduleTasks(&graph); | |
345 tile_task_worker_pool_->CheckForCompletedTasks(); | |
346 ++count; | |
347 timer_.NextLap(); | |
348 } while (!timer_.HasTimeLimitExpired()); | |
349 | |
350 TaskGraph empty; | |
351 tile_task_worker_pool_->ScheduleTasks(&empty); | |
352 RunMessageLoopUntilAllTasksHaveCompleted(); | |
353 | |
354 perf_test::PrintResult("schedule_alternate_tasks", TestModifierString(), | |
355 test_name, timer_.LapsPerSecond(), "runs/s", true); | |
356 } | |
357 | |
358 void RunScheduleAndExecuteTasksTest(const std::string& test_name, | |
359 unsigned num_raster_tasks, | |
360 unsigned num_image_decode_tasks) { | |
361 RasterTaskVector raster_tasks; | |
362 CreateRasterTasks(num_raster_tasks, num_image_decode_tasks, &raster_tasks); | |
363 | |
364 // Avoid unnecessary heap allocations by reusing the same graph. | |
365 TaskGraph graph; | |
366 | |
367 timer_.Reset(); | |
368 do { | |
369 graph.Reset(); | |
370 BuildTileTaskGraph(&graph, raster_tasks); | |
371 tile_task_worker_pool_->ScheduleTasks(&graph); | |
372 RunMessageLoopUntilAllTasksHaveCompleted(); | |
373 timer_.NextLap(); | |
374 } while (!timer_.HasTimeLimitExpired()); | |
375 | |
376 TaskGraph empty; | |
377 tile_task_worker_pool_->ScheduleTasks(&empty); | |
378 RunMessageLoopUntilAllTasksHaveCompleted(); | |
379 | |
380 perf_test::PrintResult("schedule_and_execute_tasks", TestModifierString(), | |
381 test_name, timer_.LapsPerSecond(), "runs/s", true); | |
382 } | |
383 | |
384 private: | |
385 void Create3dOutputSurfaceAndResourceProvider() { | |
386 output_surface_ = FakeOutputSurface::Create3d(context_provider_); | |
387 CHECK(output_surface_->BindToClient(&output_surface_client_)); | |
388 resource_provider_ = FakeResourceProvider::Create( | |
389 output_surface_.get(), nullptr, &gpu_memory_buffer_manager_); | |
390 } | |
391 | |
392 void CreateSoftwareOutputSurfaceAndResourceProvider() { | |
393 output_surface_ = FakeOutputSurface::CreateSoftware( | |
394 base::WrapUnique(new SoftwareOutputDevice)); | |
395 CHECK(output_surface_->BindToClient(&output_surface_client_)); | |
396 resource_provider_ = FakeResourceProvider::Create( | |
397 output_surface_.get(), &shared_bitmap_manager_, nullptr); | |
398 } | |
399 | |
400 std::string TestModifierString() const { | |
401 switch (GetParam()) { | |
402 case TILE_TASK_WORKER_POOL_TYPE_ZERO_COPY: | |
403 return std::string("_zero_copy_tile_task_worker_pool"); | |
404 case TILE_TASK_WORKER_POOL_TYPE_ONE_COPY: | |
405 return std::string("_one_copy_tile_task_worker_pool"); | |
406 case TILE_TASK_WORKER_POOL_TYPE_GPU: | |
407 return std::string("_gpu_tile_task_worker_pool"); | |
408 case TILE_TASK_WORKER_POOL_TYPE_BITMAP: | |
409 return std::string("_bitmap_tile_task_worker_pool"); | |
410 } | |
411 NOTREACHED(); | |
412 return std::string(); | |
413 } | |
414 | |
415 std::unique_ptr<TileTaskWorkerPool> tile_task_worker_pool_; | |
416 TestGpuMemoryBufferManager gpu_memory_buffer_manager_; | |
417 TestSharedBitmapManager shared_bitmap_manager_; | |
418 }; | |
419 | |
420 TEST_P(TileTaskWorkerPoolPerfTest, ScheduleTasks) { | |
421 RunScheduleTasksTest("1_0", 1, 0); | |
422 RunScheduleTasksTest("32_0", 32, 0); | |
423 RunScheduleTasksTest("1_1", 1, 1); | |
424 RunScheduleTasksTest("32_1", 32, 1); | |
425 RunScheduleTasksTest("1_4", 1, 4); | |
426 RunScheduleTasksTest("32_4", 32, 4); | |
427 } | |
428 | |
429 TEST_P(TileTaskWorkerPoolPerfTest, ScheduleAlternateTasks) { | |
430 RunScheduleAlternateTasksTest("1_0", 1, 0); | |
431 RunScheduleAlternateTasksTest("32_0", 32, 0); | |
432 RunScheduleAlternateTasksTest("1_1", 1, 1); | |
433 RunScheduleAlternateTasksTest("32_1", 32, 1); | |
434 RunScheduleAlternateTasksTest("1_4", 1, 4); | |
435 RunScheduleAlternateTasksTest("32_4", 32, 4); | |
436 } | |
437 | |
438 TEST_P(TileTaskWorkerPoolPerfTest, ScheduleAndExecuteTasks) { | |
439 RunScheduleAndExecuteTasksTest("1_0", 1, 0); | |
440 RunScheduleAndExecuteTasksTest("32_0", 32, 0); | |
441 RunScheduleAndExecuteTasksTest("1_1", 1, 1); | |
442 RunScheduleAndExecuteTasksTest("32_1", 32, 1); | |
443 RunScheduleAndExecuteTasksTest("1_4", 1, 4); | |
444 RunScheduleAndExecuteTasksTest("32_4", 32, 4); | |
445 } | |
446 | |
447 INSTANTIATE_TEST_CASE_P(TileTaskWorkerPoolPerfTests, | |
448 TileTaskWorkerPoolPerfTest, | |
449 ::testing::Values(TILE_TASK_WORKER_POOL_TYPE_ZERO_COPY, | |
450 TILE_TASK_WORKER_POOL_TYPE_ONE_COPY, | |
451 TILE_TASK_WORKER_POOL_TYPE_GPU, | |
452 TILE_TASK_WORKER_POOL_TYPE_BITMAP)); | |
453 | |
454 class TileTaskWorkerPoolCommonPerfTest : public TileTaskWorkerPoolPerfTestBase, | |
455 public testing::Test { | |
456 public: | |
457 // Overridden from testing::Test: | |
458 void SetUp() override { | |
459 output_surface_ = FakeOutputSurface::Create3d(context_provider_); | |
460 CHECK(output_surface_->BindToClient(&output_surface_client_)); | |
461 resource_provider_ = | |
462 FakeResourceProvider::Create(output_surface_.get(), nullptr); | |
463 } | |
464 | |
465 void RunBuildTileTaskGraphTest(const std::string& test_name, | |
466 unsigned num_raster_tasks, | |
467 unsigned num_image_decode_tasks) { | |
468 RasterTaskVector raster_tasks; | |
469 CreateRasterTasks(num_raster_tasks, num_image_decode_tasks, &raster_tasks); | |
470 | |
471 // Avoid unnecessary heap allocations by reusing the same graph. | |
472 TaskGraph graph; | |
473 | |
474 timer_.Reset(); | |
475 do { | |
476 graph.Reset(); | |
477 BuildTileTaskGraph(&graph, raster_tasks); | |
478 timer_.NextLap(); | |
479 } while (!timer_.HasTimeLimitExpired()); | |
480 | |
481 perf_test::PrintResult("build_raster_task_graph", "", test_name, | |
482 timer_.LapsPerSecond(), "runs/s", true); | |
483 } | |
484 }; | |
485 | |
486 TEST_F(TileTaskWorkerPoolCommonPerfTest, BuildTileTaskGraph) { | |
487 RunBuildTileTaskGraphTest("1_0", 1, 0); | |
488 RunBuildTileTaskGraphTest("32_0", 32, 0); | |
489 RunBuildTileTaskGraphTest("1_1", 1, 1); | |
490 RunBuildTileTaskGraphTest("32_1", 32, 1); | |
491 RunBuildTileTaskGraphTest("1_4", 1, 4); | |
492 RunBuildTileTaskGraphTest("32_4", 32, 4); | |
493 } | |
494 | |
495 } // namespace | |
496 } // namespace cc | |
OLD | NEW |