Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(323)

Side by Side Diff: cc/resources/tile_manager.cc

Issue 900073003: cc: Rework how picture layer tiling set gets into raster queues. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: removed unrelated changes Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2012 The Chromium Authors. All rights reserved. 1 // Copyright 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "cc/resources/tile_manager.h" 5 #include "cc/resources/tile_manager.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <limits> 8 #include <limits>
9 #include <string> 9 #include <string>
10 10
(...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after
256 256
257 // This should finish all pending tasks and release any uninitialized 257 // This should finish all pending tasks and release any uninitialized
258 // resources. 258 // resources.
259 tile_task_runner_->Shutdown(); 259 tile_task_runner_->Shutdown();
260 tile_task_runner_->CheckForCompletedTasks(); 260 tile_task_runner_->CheckForCompletedTasks();
261 261
262 FreeResourcesForReleasedTiles(); 262 FreeResourcesForReleasedTiles();
263 CleanUpReleasedTiles(); 263 CleanUpReleasedTiles();
264 } 264 }
265 265
266 void TileManager::RegisterPictureLayerTilingSet(
enne (OOO) 2015/02/10 21:28:31 This is way better than building pairs every time.
vmpstr 2015/02/11 21:37:16 This is meant to be a cleanup, but I'll get some p
267 int layer_id,
268 WhichTree tree,
269 PictureLayerTilingSet* tiling_set) {
270 auto& paired_tiling_set = paired_picture_layer_tiling_sets_[layer_id];
271 if (tree == ACTIVE_TREE) {
272 DCHECK(!paired_tiling_set.active);
273 paired_tiling_set.active = tiling_set;
274 } else {
275 DCHECK(!paired_tiling_set.pending);
276 paired_tiling_set.pending = tiling_set;
277 }
278 }
279
280 void TileManager::UnregisterPictureLayerTilingSet(int layer_id,
281 WhichTree tree) {
282 auto paired_tiling_set_it = paired_picture_layer_tiling_sets_.find(layer_id);
283 DCHECK(paired_tiling_set_it != paired_picture_layer_tiling_sets_.end());
284
285 auto& paired_tiling_set = paired_tiling_set_it->second;
286 if (tree == ACTIVE_TREE) {
287 DCHECK(paired_tiling_set.active);
288 paired_tiling_set.active = nullptr;
289 } else {
290 DCHECK(paired_tiling_set.pending);
291 paired_tiling_set.pending = nullptr;
292 }
293
294 if (!paired_tiling_set.active && !paired_tiling_set.pending)
295 paired_picture_layer_tiling_sets_.erase(paired_tiling_set_it);
296 }
297
266 void TileManager::Release(Tile* tile) { 298 void TileManager::Release(Tile* tile) {
267 released_tiles_.push_back(tile); 299 released_tiles_.push_back(tile);
268 } 300 }
269 301
270 TaskSetCollection TileManager::TasksThatShouldBeForcedToComplete() const { 302 TaskSetCollection TileManager::TasksThatShouldBeForcedToComplete() const {
271 TaskSetCollection tasks_that_should_be_forced_to_complete; 303 TaskSetCollection tasks_that_should_be_forced_to_complete;
272 if (global_state_.tree_priority != SMOOTHNESS_TAKES_PRIORITY) 304 if (global_state_.tree_priority != SMOOTHNESS_TAKES_PRIORITY)
273 tasks_that_should_be_forced_to_complete[REQUIRED_FOR_ACTIVATION] = true; 305 tasks_that_should_be_forced_to_complete[REQUIRED_FOR_ACTIVATION] = true;
274 return tasks_that_should_be_forced_to_complete; 306 return tasks_that_should_be_forced_to_complete;
275 } 307 }
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
353 if (!did_check_for_completed_tasks_since_last_schedule_tasks_) { 385 if (!did_check_for_completed_tasks_since_last_schedule_tasks_) {
354 tile_task_runner_->CheckForCompletedTasks(); 386 tile_task_runner_->CheckForCompletedTasks();
355 did_check_for_completed_tasks_since_last_schedule_tasks_ = true; 387 did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
356 } 388 }
357 389
358 FreeResourcesForReleasedTiles(); 390 FreeResourcesForReleasedTiles();
359 CleanUpReleasedTiles(); 391 CleanUpReleasedTiles();
360 392
361 TileVector tiles_that_need_to_be_rasterized; 393 TileVector tiles_that_need_to_be_rasterized;
362 scoped_ptr<RasterTilePriorityQueue> raster_priority_queue( 394 scoped_ptr<RasterTilePriorityQueue> raster_priority_queue(
363 client_->BuildRasterQueue(global_state_.tree_priority, 395 BuildRasterQueue(RasterTilePriorityQueue::Type::ALL));
364 RasterTilePriorityQueue::Type::ALL));
365 // Inform the client that will likely require a draw if the top tile is 396 // Inform the client that will likely require a draw if the top tile is
366 // required for draw. 397 // required for draw.
367 client_->SetIsLikelyToRequireADraw( 398 client_->SetIsLikelyToRequireADraw(
368 !raster_priority_queue->IsEmpty() && 399 !raster_priority_queue->IsEmpty() &&
369 raster_priority_queue->Top()->required_for_draw()); 400 raster_priority_queue->Top()->required_for_draw());
370 AssignGpuMemoryToTiles(raster_priority_queue.get(), 401 AssignGpuMemoryToTiles(raster_priority_queue.get(),
371 scheduled_raster_task_limit_, 402 scheduled_raster_task_limit_,
372 &tiles_that_need_to_be_rasterized); 403 &tiles_that_need_to_be_rasterized);
373 404
374 // Schedule tile tasks. 405 // Schedule tile tasks.
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
406 437
407 DCHECK(rasterizer_->GetPrepareTilesMode() != 438 DCHECK(rasterizer_->GetPrepareTilesMode() !=
408 PrepareTilesMode::RASTERIZE_PRIORITIZED_TILES); 439 PrepareTilesMode::RASTERIZE_PRIORITIZED_TILES);
409 440
410 global_state_ = state; 441 global_state_ = state;
411 442
412 FreeResourcesForReleasedTiles(); 443 FreeResourcesForReleasedTiles();
413 CleanUpReleasedTiles(); 444 CleanUpReleasedTiles();
414 445
415 scoped_ptr<RasterTilePriorityQueue> required_for_draw_queue( 446 scoped_ptr<RasterTilePriorityQueue> required_for_draw_queue(
416 client_->BuildRasterQueue( 447 BuildRasterQueue(RasterTilePriorityQueue::Type::REQUIRED_FOR_DRAW));
417 global_state_.tree_priority,
418 RasterTilePriorityQueue::Type::REQUIRED_FOR_DRAW));
419 TileVector tiles_that_need_to_be_rasterized; 448 TileVector tiles_that_need_to_be_rasterized;
420 AssignGpuMemoryToTiles(required_for_draw_queue.get(), 449 AssignGpuMemoryToTiles(required_for_draw_queue.get(),
421 std::numeric_limits<size_t>::max(), 450 std::numeric_limits<size_t>::max(),
422 &tiles_that_need_to_be_rasterized); 451 &tiles_that_need_to_be_rasterized);
423 452
424 // We must reduce the amount of unused resources before calling 453 // We must reduce the amount of unused resources before calling
425 // RunTasks to prevent usage from rising above limits. 454 // RunTasks to prevent usage from rising above limits.
426 resource_pool_->ReduceResourceUsage(); 455 resource_pool_->ReduceResourceUsage();
427 456
428 // Run and complete all raster task synchronously. 457 // Run and complete all raster task synchronously.
429 rasterizer_->RasterizeTiles( 458 rasterizer_->RasterizeTiles(
430 tiles_that_need_to_be_rasterized, resource_pool_, 459 tiles_that_need_to_be_rasterized, resource_pool_,
431 tile_task_runner_->GetResourceFormat(), 460 tile_task_runner_->GetResourceFormat(),
432 base::Bind(&TileManager::UpdateTileDrawInfo, base::Unretained(this))); 461 base::Bind(&TileManager::UpdateTileDrawInfo, base::Unretained(this)));
433 462
434 // Use on-demand raster for any required-for-draw tiles that have not been 463 // Use on-demand raster for any required-for-draw tiles that have not been
435 // assigned memory after reaching a steady memory state. 464 // assigned memory after reaching a steady memory state.
436 // TODO(hendrikw): Figure out why this would improve jank on some tests - See 465 // TODO(hendrikw): Figure out why this would improve jank on some tests - See
437 // crbug.com/449288 466 // crbug.com/449288
438 required_for_draw_queue = client_->BuildRasterQueue( 467 required_for_draw_queue =
439 global_state_.tree_priority, 468 BuildRasterQueue(RasterTilePriorityQueue::Type::REQUIRED_FOR_DRAW);
440 RasterTilePriorityQueue::Type::REQUIRED_FOR_DRAW);
441 469
442 // Use on-demand raster for any tiles that have not been been assigned 470 // Use on-demand raster for any tiles that have not been been assigned
443 // memory. This ensures that we draw even when OOM. 471 // memory. This ensures that we draw even when OOM.
444 for (; !required_for_draw_queue->IsEmpty(); required_for_draw_queue->Pop()) { 472 for (; !required_for_draw_queue->IsEmpty(); required_for_draw_queue->Pop()) {
445 Tile* tile = required_for_draw_queue->Top(); 473 Tile* tile = required_for_draw_queue->Top();
446 tile->draw_info().set_rasterize_on_demand(); 474 tile->draw_info().set_rasterize_on_demand();
447 client_->NotifyTileStateChanged(tile); 475 client_->NotifyTileStateChanged(tile);
448 } 476 }
449 477
450 TRACE_EVENT_INSTANT1("cc", "DidRasterize", TRACE_EVENT_SCOPE_THREAD, "state", 478 TRACE_EVENT_INSTANT1("cc", "DidRasterize", TRACE_EVENT_SCOPE_THREAD, "state",
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
492 global_state_.AsValueInto(state); 520 global_state_.AsValueInto(state);
493 state->EndDictionary(); 521 state->EndDictionary();
494 } 522 }
495 523
496 scoped_ptr<EvictionTilePriorityQueue> 524 scoped_ptr<EvictionTilePriorityQueue>
497 TileManager::FreeTileResourcesUntilUsageIsWithinLimit( 525 TileManager::FreeTileResourcesUntilUsageIsWithinLimit(
498 scoped_ptr<EvictionTilePriorityQueue> eviction_priority_queue, 526 scoped_ptr<EvictionTilePriorityQueue> eviction_priority_queue,
499 const MemoryUsage& limit, 527 const MemoryUsage& limit,
500 MemoryUsage* usage) { 528 MemoryUsage* usage) {
501 while (usage->Exceeds(limit)) { 529 while (usage->Exceeds(limit)) {
502 if (!eviction_priority_queue) { 530 if (!eviction_priority_queue)
503 eviction_priority_queue = 531 eviction_priority_queue = BuildEvictionQueue();
504 client_->BuildEvictionQueue(global_state_.tree_priority);
505 }
506 if (eviction_priority_queue->IsEmpty()) 532 if (eviction_priority_queue->IsEmpty())
507 break; 533 break;
508 534
509 Tile* tile = eviction_priority_queue->Top(); 535 Tile* tile = eviction_priority_queue->Top();
510 *usage -= MemoryUsage::FromTile(tile); 536 *usage -= MemoryUsage::FromTile(tile);
511 FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(tile); 537 FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(tile);
512 eviction_priority_queue->Pop(); 538 eviction_priority_queue->Pop();
513 } 539 }
514 return eviction_priority_queue; 540 return eviction_priority_queue;
515 } 541 }
516 542
517 scoped_ptr<EvictionTilePriorityQueue> 543 scoped_ptr<EvictionTilePriorityQueue>
518 TileManager::FreeTileResourcesWithLowerPriorityUntilUsageIsWithinLimit( 544 TileManager::FreeTileResourcesWithLowerPriorityUntilUsageIsWithinLimit(
519 scoped_ptr<EvictionTilePriorityQueue> eviction_priority_queue, 545 scoped_ptr<EvictionTilePriorityQueue> eviction_priority_queue,
520 const MemoryUsage& limit, 546 const MemoryUsage& limit,
521 const TilePriority& other_priority, 547 const TilePriority& other_priority,
522 MemoryUsage* usage) { 548 MemoryUsage* usage) {
523 while (usage->Exceeds(limit)) { 549 while (usage->Exceeds(limit)) {
524 if (!eviction_priority_queue) { 550 if (!eviction_priority_queue)
525 eviction_priority_queue = 551 eviction_priority_queue = BuildEvictionQueue();
526 client_->BuildEvictionQueue(global_state_.tree_priority);
527 }
528 if (eviction_priority_queue->IsEmpty()) 552 if (eviction_priority_queue->IsEmpty())
529 break; 553 break;
530 554
531 Tile* tile = eviction_priority_queue->Top(); 555 Tile* tile = eviction_priority_queue->Top();
532 if (!other_priority.IsHigherPriorityThan(tile->combined_priority())) 556 if (!other_priority.IsHigherPriorityThan(tile->combined_priority()))
533 break; 557 break;
534 558
535 *usage -= MemoryUsage::FromTile(tile); 559 *usage -= MemoryUsage::FromTile(tile);
536 FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(tile); 560 FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(tile);
537 eviction_priority_queue->Pop(); 561 eviction_priority_queue->Pop();
(...skipping 328 matching lines...) Expand 10 before | Expand all | Expand 10 after
866 890
867 void TileManager::SetTileTaskRunnerForTesting( 891 void TileManager::SetTileTaskRunnerForTesting(
868 TileTaskRunner* tile_task_runner) { 892 TileTaskRunner* tile_task_runner) {
869 tile_task_runner_ = tile_task_runner; 893 tile_task_runner_ = tile_task_runner;
870 tile_task_runner_->SetClient(this); 894 tile_task_runner_->SetClient(this);
871 } 895 }
872 896
873 bool TileManager::AreRequiredTilesReadyToDraw( 897 bool TileManager::AreRequiredTilesReadyToDraw(
874 RasterTilePriorityQueue::Type type) const { 898 RasterTilePriorityQueue::Type type) const {
875 scoped_ptr<RasterTilePriorityQueue> raster_priority_queue( 899 scoped_ptr<RasterTilePriorityQueue> raster_priority_queue(
876 client_->BuildRasterQueue(global_state_.tree_priority, type)); 900 BuildRasterQueue(type));
877 // It is insufficient to check whether the raster queue we constructed is 901 // It is insufficient to check whether the raster queue we constructed is
878 // empty. The reason for this is that there are situations (rasterize on 902 // empty. The reason for this is that there are situations (rasterize on
879 // demand) when the tile both needs raster and it's ready to draw. Hence, we 903 // demand) when the tile both needs raster and it's ready to draw. Hence, we
880 // have to iterate the queue to check whether the required tiles are ready to 904 // have to iterate the queue to check whether the required tiles are ready to
881 // draw. 905 // draw.
882 for (; !raster_priority_queue->IsEmpty(); raster_priority_queue->Pop()) { 906 for (; !raster_priority_queue->IsEmpty(); raster_priority_queue->Pop()) {
883 if (!raster_priority_queue->Top()->IsReadyToDraw()) 907 if (!raster_priority_queue->Top()->IsReadyToDraw())
884 return false; 908 return false;
885 } 909 }
886 return true; 910 return true;
887 } 911 }
888 bool TileManager::IsReadyToActivate() const { 912 bool TileManager::IsReadyToActivate() const {
889 TRACE_EVENT0("cc", "TileManager::IsReadyToActivate"); 913 TRACE_EVENT0("cc", "TileManager::IsReadyToActivate");
890 return AreRequiredTilesReadyToDraw( 914 return AreRequiredTilesReadyToDraw(
891 RasterTilePriorityQueue::Type::REQUIRED_FOR_ACTIVATION); 915 RasterTilePriorityQueue::Type::REQUIRED_FOR_ACTIVATION);
892 } 916 }
893 917
894 bool TileManager::IsReadyToDraw() const { 918 bool TileManager::IsReadyToDraw() const {
895 TRACE_EVENT0("cc", "TileManager::IsReadyToDraw"); 919 TRACE_EVENT0("cc", "TileManager::IsReadyToDraw");
896 return AreRequiredTilesReadyToDraw( 920 return AreRequiredTilesReadyToDraw(
897 RasterTilePriorityQueue::Type::REQUIRED_FOR_DRAW); 921 RasterTilePriorityQueue::Type::REQUIRED_FOR_DRAW);
898 } 922 }
899 923
924 scoped_ptr<RasterTilePriorityQueue> TileManager::BuildRasterQueue(
925 RasterTilePriorityQueue::Type type) const {
926 TRACE_EVENT0("cc", "TileManager::BuildRasterQueue");
927 return RasterTilePriorityQueue::Create(paired_picture_layer_tiling_sets_,
928 client_->PendingTreeExists(),
929 global_state_.tree_priority, type);
930 }
931
932 scoped_ptr<EvictionTilePriorityQueue> TileManager::BuildEvictionQueue() const {
933 TRACE_EVENT0("cc", "TileManager::BuildEvictionQueue");
934 return EvictionTilePriorityQueue::Create(paired_picture_layer_tiling_sets_,
935 client_->PendingTreeExists(),
936 global_state_.tree_priority);
937 }
938
900 void TileManager::NotifyReadyToActivate() { 939 void TileManager::NotifyReadyToActivate() {
901 TRACE_EVENT0("cc", "TileManager::NotifyReadyToActivate"); 940 TRACE_EVENT0("cc", "TileManager::NotifyReadyToActivate");
902 if (did_notify_ready_to_activate_) 941 if (did_notify_ready_to_activate_)
903 return; 942 return;
904 client_->NotifyReadyToActivate(); 943 client_->NotifyReadyToActivate();
905 did_notify_ready_to_activate_ = true; 944 did_notify_ready_to_activate_ = true;
906 } 945 }
907 946
908 void TileManager::NotifyReadyToDraw() { 947 void TileManager::NotifyReadyToDraw() {
909 TRACE_EVENT0("cc", "TileManager::NotifyReadyToDraw"); 948 TRACE_EVENT0("cc", "TileManager::NotifyReadyToDraw");
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
942 } 981 }
943 982
944 void TileManager::CheckIfMoreTilesNeedToBePrepared() { 983 void TileManager::CheckIfMoreTilesNeedToBePrepared() {
945 tile_task_runner_->CheckForCompletedTasks(); 984 tile_task_runner_->CheckForCompletedTasks();
946 did_check_for_completed_tasks_since_last_schedule_tasks_ = true; 985 did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
947 986
948 // When OOM, keep re-assigning memory until we reach a steady state 987 // When OOM, keep re-assigning memory until we reach a steady state
949 // where top-priority tiles are initialized. 988 // where top-priority tiles are initialized.
950 TileVector tiles_that_need_to_be_rasterized; 989 TileVector tiles_that_need_to_be_rasterized;
951 scoped_ptr<RasterTilePriorityQueue> raster_priority_queue( 990 scoped_ptr<RasterTilePriorityQueue> raster_priority_queue(
952 client_->BuildRasterQueue(global_state_.tree_priority, 991 BuildRasterQueue(RasterTilePriorityQueue::Type::ALL));
953 RasterTilePriorityQueue::Type::ALL));
954 AssignGpuMemoryToTiles(raster_priority_queue.get(), 992 AssignGpuMemoryToTiles(raster_priority_queue.get(),
955 scheduled_raster_task_limit_, 993 scheduled_raster_task_limit_,
956 &tiles_that_need_to_be_rasterized); 994 &tiles_that_need_to_be_rasterized);
957 995
958 // |tiles_that_need_to_be_rasterized| will be empty when we reach a 996 // |tiles_that_need_to_be_rasterized| will be empty when we reach a
959 // steady memory state. Keep scheduling tasks until we reach this state. 997 // steady memory state. Keep scheduling tasks until we reach this state.
960 if (!tiles_that_need_to_be_rasterized.empty()) { 998 if (!tiles_that_need_to_be_rasterized.empty()) {
961 ScheduleTasks(tiles_that_need_to_be_rasterized); 999 ScheduleTasks(tiles_that_need_to_be_rasterized);
962 return; 1000 return;
963 } 1001 }
(...skipping 12 matching lines...) Expand all
976 global_state_.tree_priority != SMOOTHNESS_TAKES_PRIORITY && 1014 global_state_.tree_priority != SMOOTHNESS_TAKES_PRIORITY &&
977 global_state_.memory_limit_policy != ALLOW_NOTHING; 1015 global_state_.memory_limit_policy != ALLOW_NOTHING;
978 1016
979 // Use on-demand raster for any required-for-activation tiles that have 1017 // Use on-demand raster for any required-for-activation tiles that have
980 // not been been assigned memory after reaching a steady memory state. This 1018 // not been been assigned memory after reaching a steady memory state. This
981 // ensures that we activate even when OOM. Note that we can't reuse the queue 1019 // ensures that we activate even when OOM. Note that we can't reuse the queue
982 // we used for AssignGpuMemoryToTiles, since the AssignGpuMemoryToTiles call 1020 // we used for AssignGpuMemoryToTiles, since the AssignGpuMemoryToTiles call
983 // could have evicted some tiles that would not be picked up by the old raster 1021 // could have evicted some tiles that would not be picked up by the old raster
984 // queue. 1022 // queue.
985 scoped_ptr<RasterTilePriorityQueue> required_for_activation_queue( 1023 scoped_ptr<RasterTilePriorityQueue> required_for_activation_queue(
986 client_->BuildRasterQueue( 1024 BuildRasterQueue(RasterTilePriorityQueue::Type::REQUIRED_FOR_ACTIVATION));
987 global_state_.tree_priority,
988 RasterTilePriorityQueue::Type::REQUIRED_FOR_ACTIVATION));
989 1025
990 // If we have tiles to mark as rasterize on demand, but we don't allow 1026 // If we have tiles to mark as rasterize on demand, but we don't allow
991 // rasterize on demand, then skip activation and return early. 1027 // rasterize on demand, then skip activation and return early.
992 if (!required_for_activation_queue->IsEmpty() && !allow_rasterize_on_demand) 1028 if (!required_for_activation_queue->IsEmpty() && !allow_rasterize_on_demand)
993 return; 1029 return;
994 1030
995 // Mark required tiles as rasterize on demand. 1031 // Mark required tiles as rasterize on demand.
996 for (; !required_for_activation_queue->IsEmpty(); 1032 for (; !required_for_activation_queue->IsEmpty();
997 required_for_activation_queue->Pop()) { 1033 required_for_activation_queue->Pop()) {
998 Tile* tile = required_for_activation_queue->Top(); 1034 Tile* tile = required_for_activation_queue->Top();
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
1048 result -= other; 1084 result -= other;
1049 return result; 1085 return result;
1050 } 1086 }
1051 1087
1052 bool TileManager::MemoryUsage::Exceeds(const MemoryUsage& limit) const { 1088 bool TileManager::MemoryUsage::Exceeds(const MemoryUsage& limit) const {
1053 return memory_bytes_ > limit.memory_bytes_ || 1089 return memory_bytes_ > limit.memory_bytes_ ||
1054 resource_count_ > limit.resource_count_; 1090 resource_count_ > limit.resource_count_;
1055 } 1091 }
1056 1092
1057 } // namespace cc 1093 } // namespace cc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698