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 30 namespace cc { 31 namespace { 32 33 class 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 65 class 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 96 enum 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 104 static const int kTimeLimitMillis = 2000; 105 static const int kWarmupRuns = 5; 106 static const int kTimeCheckInterval = 10; 107 108 class 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 132 class 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 165 class 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 224 class 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 442 TEST_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 451 TEST_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 460 TEST_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 469 INSTANTIATE_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 477 class 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 516 TEST_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