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

Side by Side Diff: cc/trees/thread_proxy.cc

Issue 23796002: cc: Implement deadine scheduling disabled by default (Closed) Base URL: http://git.chromium.org/chromium/src.git@schedReadback4
Patch Set: Rebase on epenner's ManageTiles patch Created 7 years, 3 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
« no previous file with comments | « cc/trees/thread_proxy.h ('k') | chrome/browser/chromeos/login/chrome_restart_request.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2011 The Chromium Authors. All rights reserved. 1 // Copyright 2011 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/trees/thread_proxy.h" 5 #include "cc/trees/thread_proxy.h"
6 6
7 #include <string> 7 #include <string>
8 8
9 #include "base/auto_reset.h" 9 #include "base/auto_reset.h"
10 #include "base/bind.h" 10 #include "base/bind.h"
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
73 created_offscreen_context_provider_(false), 73 created_offscreen_context_provider_(false),
74 layer_tree_host_(layer_tree_host), 74 layer_tree_host_(layer_tree_host),
75 started_(false), 75 started_(false),
76 textures_acquired_(true), 76 textures_acquired_(true),
77 in_composite_and_readback_(false), 77 in_composite_and_readback_(false),
78 manage_tiles_pending_(false), 78 manage_tiles_pending_(false),
79 commit_waits_for_activation_(false), 79 commit_waits_for_activation_(false),
80 inside_commit_(false), 80 inside_commit_(false),
81 weak_factory_on_impl_thread_(this), 81 weak_factory_on_impl_thread_(this),
82 weak_factory_(this), 82 weak_factory_(this),
83 frame_did_draw_(false),
83 begin_frame_sent_to_main_thread_completion_event_on_impl_thread_(NULL), 84 begin_frame_sent_to_main_thread_completion_event_on_impl_thread_(NULL),
84 readback_request_on_impl_thread_(NULL), 85 readback_request_on_impl_thread_(NULL),
85 commit_completion_event_on_impl_thread_(NULL), 86 commit_completion_event_on_impl_thread_(NULL),
86 completion_event_for_commit_held_on_tree_activation_(NULL), 87 completion_event_for_commit_held_on_tree_activation_(NULL),
87 texture_acquisition_completion_event_on_impl_thread_(NULL), 88 texture_acquisition_completion_event_on_impl_thread_(NULL),
88 next_frame_is_newly_committed_frame_on_impl_thread_(false), 89 next_frame_is_newly_committed_frame_on_impl_thread_(false),
89 throttle_frame_production_( 90 throttle_frame_production_(
90 layer_tree_host->settings().throttle_frame_production), 91 layer_tree_host->settings().throttle_frame_production),
91 begin_frame_scheduling_enabled_( 92 begin_frame_scheduling_enabled_(
92 layer_tree_host->settings().begin_frame_scheduling_enabled), 93 layer_tree_host->settings().begin_frame_scheduling_enabled),
(...skipping 297 matching lines...) Expand 10 before | Expand all | Expand 10 after
390 Proxy::MainThreadTaskRunner()->PostTask( 391 Proxy::MainThreadTaskRunner()->PostTask(
391 FROM_HERE, 392 FROM_HERE,
392 base::Bind(&ThreadProxy::DidCompleteSwapBuffers, main_thread_weak_ptr_)); 393 base::Bind(&ThreadProxy::DidCompleteSwapBuffers, main_thread_weak_ptr_));
393 } 394 }
394 395
395 void ThreadProxy::SetNeedsBeginFrameOnImplThread(bool enable) { 396 void ThreadProxy::SetNeedsBeginFrameOnImplThread(bool enable) {
396 DCHECK(IsImplThread()); 397 DCHECK(IsImplThread());
397 TRACE_EVENT1("cc", "ThreadProxy::SetNeedsBeginFrameOnImplThread", 398 TRACE_EVENT1("cc", "ThreadProxy::SetNeedsBeginFrameOnImplThread",
398 "enable", enable); 399 "enable", enable);
399 layer_tree_host_impl_->SetNeedsBeginFrame(enable); 400 layer_tree_host_impl_->SetNeedsBeginFrame(enable);
401 UpdateBackgroundAnimateTicking();
400 } 402 }
401 403
402 void ThreadProxy::BeginFrameOnImplThread(const BeginFrameArgs& args) { 404 void ThreadProxy::BeginFrameOnImplThread(const BeginFrameArgs& args) {
403 DCHECK(IsImplThread()); 405 DCHECK(IsImplThread());
404 TRACE_EVENT0("cc", "ThreadProxy::BeginFrameOnImplThread"); 406 TRACE_EVENT0("cc", "ThreadProxy::BeginFrameOnImplThread");
407
408 base::TimeTicks monotonic_time =
409 layer_tree_host_impl_->CurrentFrameTimeTicks();
410 base::Time wall_clock_time = layer_tree_host_impl_->CurrentFrameTime();
411 if (layer_tree_host_impl_->active_tree()->root_layer())
412 layer_tree_host_impl_->Animate(monotonic_time, wall_clock_time);
413
414 // Reinitialize for the current frame.
415 frame_did_draw_ = false;
416
405 scheduler_on_impl_thread_->BeginFrame(args); 417 scheduler_on_impl_thread_->BeginFrame(args);
406 } 418 }
407 419
420 void ThreadProxy::DidBeginFrameDeadlineOnImplThread() {
421 // Do not start animations if we skip drawing the frame to avoid
422 // checkerboarding.
423 if (layer_tree_host_impl_->active_tree()->root_layer()) {
424 layer_tree_host_impl_->UpdateAnimationState(
425 frame_did_draw_ || !layer_tree_host_impl_->CanDraw());
enne (OOO) 2013/09/13 22:28:51 Maybe I just missed this in previous patches, but
brianderson 2013/09/13 22:50:33 Since we have a BeginFrame+deadline interval (in w
enne (OOO) 2013/09/13 23:21:54 With this patch, the animation time is the previou
brianderson 2013/09/14 00:09:59 I think the naming of the timing functions is a li
ajuma 2013/09/14 00:19:40 They should stay balanced. In the old code, we wer
ajuma 2013/09/14 00:19:40 The call to Animate moves animations into a Starti
426 }
427 layer_tree_host_impl_->ResetCurrentFrameTimeForNextFrame();
428 }
429
408 void ThreadProxy::OnCanDrawStateChanged(bool can_draw) { 430 void ThreadProxy::OnCanDrawStateChanged(bool can_draw) {
409 DCHECK(IsImplThread()); 431 DCHECK(IsImplThread());
410 TRACE_EVENT1( 432 TRACE_EVENT1(
411 "cc", "ThreadProxy::OnCanDrawStateChanged", "can_draw", can_draw); 433 "cc", "ThreadProxy::OnCanDrawStateChanged", "can_draw", can_draw);
412 scheduler_on_impl_thread_->SetCanDraw(can_draw); 434 scheduler_on_impl_thread_->SetCanDraw(can_draw);
413 UpdateBackgroundAnimateTicking(); 435 UpdateBackgroundAnimateTicking();
414 } 436 }
415 437
416 void ThreadProxy::NotifyReadyToActivate() { 438 void ThreadProxy::NotifyReadyToActivate() {
417 TRACE_EVENT0("cc", "ThreadProxy::NotifyReadyToActivate"); 439 TRACE_EVENT0("cc", "ThreadProxy::NotifyReadyToActivate");
(...skipping 568 matching lines...) Expand 10 before | Expand all | Expand 10 after
986 commit_completion_event_on_impl_thread_->Signal(); 1008 commit_completion_event_on_impl_thread_->Signal();
987 commit_completion_event_on_impl_thread_ = NULL; 1009 commit_completion_event_on_impl_thread_ = NULL;
988 } 1010 }
989 1011
990 commit_waits_for_activation_ = false; 1012 commit_waits_for_activation_ = false;
991 1013
992 commit_complete_time_ = base::TimeTicks::HighResNow(); 1014 commit_complete_time_ = base::TimeTicks::HighResNow();
993 begin_frame_to_commit_duration_history_.InsertSample( 1015 begin_frame_to_commit_duration_history_.InsertSample(
994 commit_complete_time_ - begin_frame_sent_to_main_thread_time_); 1016 commit_complete_time_ - begin_frame_sent_to_main_thread_time_);
995 1017
1018 // The commit may have added animations, requiring us to start
enne (OOO) 2013/09/13 22:28:51 Can you mention that this is only true if impl-sid
brianderson 2013/09/13 22:50:33 Now that you've pointed that out, is this call eve
ajuma 2013/09/14 00:19:40 This was added because a test was failing in a sit
1019 // background ticking.
1020 UpdateBackgroundAnimateTicking();
1021
996 // SetVisible kicks off the next scheduler action, so this must be last. 1022 // SetVisible kicks off the next scheduler action, so this must be last.
997 scheduler_on_impl_thread_->SetVisible(layer_tree_host_impl_->visible()); 1023 scheduler_on_impl_thread_->SetVisible(layer_tree_host_impl_->visible());
998 } 1024 }
999 1025
1000 void ThreadProxy::ScheduledActionUpdateVisibleTiles() { 1026 void ThreadProxy::ScheduledActionUpdateVisibleTiles() {
1001 DCHECK(IsImplThread()); 1027 DCHECK(IsImplThread());
1002 TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionUpdateVisibleTiles"); 1028 TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionUpdateVisibleTiles");
1003 layer_tree_host_impl_->UpdateVisibleTiles(); 1029 layer_tree_host_impl_->UpdateVisibleTiles();
1004 } 1030 }
1005 1031
(...skipping 22 matching lines...) Expand all
1028 result.did_readback = false; 1054 result.did_readback = false;
1029 DCHECK(IsImplThread()); 1055 DCHECK(IsImplThread());
1030 DCHECK(layer_tree_host_impl_.get()); 1056 DCHECK(layer_tree_host_impl_.get());
1031 if (!layer_tree_host_impl_) 1057 if (!layer_tree_host_impl_)
1032 return result; 1058 return result;
1033 1059
1034 DCHECK(layer_tree_host_impl_->renderer()); 1060 DCHECK(layer_tree_host_impl_->renderer());
1035 if (!layer_tree_host_impl_->renderer()) 1061 if (!layer_tree_host_impl_->renderer())
1036 return result; 1062 return result;
1037 1063
1038 base::TimeTicks monotonic_time =
1039 layer_tree_host_impl_->CurrentFrameTimeTicks();
1040 base::Time wall_clock_time = layer_tree_host_impl_->CurrentFrameTime();
1041
1042 // TODO(enne): This should probably happen post-animate.
1043 if (layer_tree_host_impl_->pending_tree())
1044 layer_tree_host_impl_->pending_tree()->UpdateDrawProperties();
1045 layer_tree_host_impl_->Animate(monotonic_time, wall_clock_time);
1046 UpdateBackgroundAnimateTicking();
1047
1048 base::TimeTicks start_time = base::TimeTicks::HighResNow(); 1064 base::TimeTicks start_time = base::TimeTicks::HighResNow();
1049 base::TimeDelta draw_duration_estimate = DrawDurationEstimate(); 1065 base::TimeDelta draw_duration_estimate = DrawDurationEstimate();
1050 base::AutoReset<bool> mark_inside(&inside_draw_, true); 1066 base::AutoReset<bool> mark_inside(&inside_draw_, true);
1051 1067
1052 // This method is called on a forced draw, regardless of whether we are able 1068 // This method is called on a forced draw, regardless of whether we are able
1053 // to produce a frame, as the calling site on main thread is blocked until its 1069 // to produce a frame, as the calling site on main thread is blocked until its
1054 // request completes, and we signal completion here. If CanDraw() is false, we 1070 // request completes, and we signal completion here. If CanDraw() is false, we
1055 // will indicate success=false to the caller, but we must still signal 1071 // will indicate success=false to the caller, but we must still signal
1056 // completion to avoid deadlock. 1072 // completion to avoid deadlock.
1057 1073
1058 // We guard PrepareToDraw() with CanDraw() because it always returns a valid 1074 // We guard PrepareToDraw() with CanDraw() because it always returns a valid
1059 // frame, so can only be used when such a frame is possible. Since 1075 // frame, so can only be used when such a frame is possible. Since
1060 // DrawLayers() depends on the result of PrepareToDraw(), it is guarded on 1076 // DrawLayers() depends on the result of PrepareToDraw(), it is guarded on
1061 // CanDraw() as well. 1077 // CanDraw() as well.
1062 1078
1063 // readback_request_on_impl_thread_ may be for the pending tree, do
1064 // not perform the readback unless explicitly requested.
1065 bool drawing_for_readback = 1079 bool drawing_for_readback =
1066 readback_requested && !!readback_request_on_impl_thread_; 1080 readback_requested && !!readback_request_on_impl_thread_;
1067 bool can_do_readback = layer_tree_host_impl_->renderer()->CanReadPixels(); 1081 bool can_do_readback = layer_tree_host_impl_->renderer()->CanReadPixels();
1068 1082
1069 LayerTreeHostImpl::FrameData frame; 1083 LayerTreeHostImpl::FrameData frame;
1070 bool draw_frame = false; 1084 bool draw_frame = false;
1071 bool start_ready_animations = true;
1072 1085
1073 if (layer_tree_host_impl_->CanDraw() && 1086 if (layer_tree_host_impl_->CanDraw() &&
1074 (!drawing_for_readback || can_do_readback)) { 1087 (!drawing_for_readback || can_do_readback)) {
1075 // If it is for a readback, make sure we draw the portion being read back. 1088 // If it is for a readback, make sure we draw the portion being read back.
1076 gfx::Rect readback_rect; 1089 gfx::Rect readback_rect;
1077 if (drawing_for_readback) 1090 if (drawing_for_readback)
1078 readback_rect = readback_request_on_impl_thread_->rect; 1091 readback_rect = readback_request_on_impl_thread_->rect;
1079 1092
1080 // Do not start animations if we skip drawing the frame to avoid
1081 // checkerboarding.
1082 if (layer_tree_host_impl_->PrepareToDraw(&frame, readback_rect) || 1093 if (layer_tree_host_impl_->PrepareToDraw(&frame, readback_rect) ||
1083 forced_draw) 1094 forced_draw)
1084 draw_frame = true; 1095 draw_frame = true;
1085 else
1086 start_ready_animations = false;
1087 } 1096 }
1088 1097
1098 frame_did_draw_ = draw_frame;
1099
1089 if (draw_frame) { 1100 if (draw_frame) {
1090 layer_tree_host_impl_->DrawLayers( 1101 layer_tree_host_impl_->DrawLayers(
1091 &frame, 1102 &frame,
1092 scheduler_on_impl_thread_->LastBeginFrameOnImplThreadTime()); 1103 scheduler_on_impl_thread_->LastBeginFrameOnImplThreadTime());
1093 result.did_draw = true; 1104 result.did_draw = true;
1094 } 1105 }
1095 layer_tree_host_impl_->DidDrawAllLayers(frame); 1106 layer_tree_host_impl_->DidDrawAllLayers(frame);
1096 layer_tree_host_impl_->UpdateAnimationState(start_ready_animations);
1097 1107
1098 // Check for a pending CompositeAndReadback. 1108 // Check for a pending CompositeAndReadback.
1099 if (drawing_for_readback) { 1109 if (drawing_for_readback) {
1100 DCHECK(!swap_requested); 1110 DCHECK(!swap_requested);
1101 result.did_readback = false; 1111 result.did_readback = false;
1102 if (draw_frame && !layer_tree_host_impl_->IsContextLost()) { 1112 if (draw_frame && !layer_tree_host_impl_->IsContextLost()) {
1103 layer_tree_host_impl_->Readback(readback_request_on_impl_thread_->pixels, 1113 layer_tree_host_impl_->Readback(readback_request_on_impl_thread_->pixels,
1104 readback_request_on_impl_thread_->rect); 1114 readback_request_on_impl_thread_->rect);
1105 result.did_readback = true; 1115 result.did_readback = true;
1106 } 1116 }
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after
1226 TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionDrawAndReadback"); 1236 TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionDrawAndReadback");
1227 bool forced_draw = true; 1237 bool forced_draw = true;
1228 bool swap_requested = false; 1238 bool swap_requested = false;
1229 bool readback_requested = true; 1239 bool readback_requested = true;
1230 return DrawSwapReadbackInternal( 1240 return DrawSwapReadbackInternal(
1231 forced_draw, swap_requested, readback_requested); 1241 forced_draw, swap_requested, readback_requested);
1232 } 1242 }
1233 1243
1234 void ThreadProxy::DidAnticipatedDrawTimeChange(base::TimeTicks time) { 1244 void ThreadProxy::DidAnticipatedDrawTimeChange(base::TimeTicks time) {
1235 if (current_resource_update_controller_on_impl_thread_) 1245 if (current_resource_update_controller_on_impl_thread_)
1236 current_resource_update_controller_on_impl_thread_ 1246 current_resource_update_controller_on_impl_thread_->PerformMoreUpdates(
1237 ->PerformMoreUpdates(time); 1247 time);
1238 layer_tree_host_impl_->ResetCurrentFrameTimeForNextFrame();
1239 } 1248 }
1240 1249
1241 base::TimeDelta ThreadProxy::DrawDurationEstimate() { 1250 base::TimeDelta ThreadProxy::DrawDurationEstimate() {
1242 base::TimeDelta historical_estimate = 1251 base::TimeDelta historical_estimate =
1243 draw_duration_history_.Percentile(kDrawDurationEstimationPercentile); 1252 draw_duration_history_.Percentile(kDrawDurationEstimationPercentile);
1244 base::TimeDelta padding = base::TimeDelta::FromMicroseconds( 1253 base::TimeDelta padding = base::TimeDelta::FromMicroseconds(
1245 kDrawDurationEstimatePaddingInMicroseconds); 1254 kDrawDurationEstimatePaddingInMicroseconds);
1246 return historical_estimate + padding; 1255 return historical_estimate + padding;
1247 } 1256 }
1248 1257
1249 base::TimeDelta ThreadProxy::BeginFrameToCommitDurationEstimate() { 1258 base::TimeDelta ThreadProxy::BeginFrameToCommitDurationEstimate() {
1250 return begin_frame_to_commit_duration_history_.Percentile( 1259 return begin_frame_to_commit_duration_history_.Percentile(
1251 kCommitAndActivationDurationEstimationPercentile); 1260 kCommitAndActivationDurationEstimationPercentile);
1252 } 1261 }
1253 1262
1254 base::TimeDelta ThreadProxy::CommitToActivateDurationEstimate() { 1263 base::TimeDelta ThreadProxy::CommitToActivateDurationEstimate() {
1255 return commit_to_activate_duration_history_.Percentile( 1264 return commit_to_activate_duration_history_.Percentile(
1256 kCommitAndActivationDurationEstimationPercentile); 1265 kCommitAndActivationDurationEstimationPercentile);
1257 } 1266 }
1258 1267
1268 void ThreadProxy::PostBeginFrameDeadline(const base::Closure& closure,
1269 base::TimeTicks deadline) {
1270 base::TimeDelta delta = deadline - base::TimeTicks::Now();
1271 if (delta <= base::TimeDelta())
1272 delta = base::TimeDelta();
1273 Proxy::ImplThreadTaskRunner()->PostDelayedTask(FROM_HERE, closure, delta);
1274 }
1275
1259 void ThreadProxy::ReadyToFinalizeTextureUpdates() { 1276 void ThreadProxy::ReadyToFinalizeTextureUpdates() {
1260 DCHECK(IsImplThread()); 1277 DCHECK(IsImplThread());
1261 scheduler_on_impl_thread_->FinishCommit(); 1278 scheduler_on_impl_thread_->FinishCommit();
1262 } 1279 }
1263 1280
1264 void ThreadProxy::DidCommitAndDrawFrame() { 1281 void ThreadProxy::DidCommitAndDrawFrame() {
1265 DCHECK(IsMainThread()); 1282 DCHECK(IsMainThread());
1266 if (!layer_tree_host_) 1283 if (!layer_tree_host_)
1267 return; 1284 return;
1268 layer_tree_host_->DidCommitAndDrawFrame(); 1285 layer_tree_host_->DidCommitAndDrawFrame();
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
1319 scheduler_on_impl_thread_->HasInitializedOutputSurface(); 1336 scheduler_on_impl_thread_->HasInitializedOutputSurface();
1320 completion->Signal(); 1337 completion->Signal();
1321 } 1338 }
1322 1339
1323 void ThreadProxy::InitializeImplOnImplThread(CompletionEvent* completion) { 1340 void ThreadProxy::InitializeImplOnImplThread(CompletionEvent* completion) {
1324 TRACE_EVENT0("cc", "ThreadProxy::InitializeImplOnImplThread"); 1341 TRACE_EVENT0("cc", "ThreadProxy::InitializeImplOnImplThread");
1325 DCHECK(IsImplThread()); 1342 DCHECK(IsImplThread());
1326 layer_tree_host_impl_ = layer_tree_host_->CreateLayerTreeHostImpl(this); 1343 layer_tree_host_impl_ = layer_tree_host_->CreateLayerTreeHostImpl(this);
1327 const LayerTreeSettings& settings = layer_tree_host_->settings(); 1344 const LayerTreeSettings& settings = layer_tree_host_->settings();
1328 SchedulerSettings scheduler_settings; 1345 SchedulerSettings scheduler_settings;
1346 scheduler_settings.deadline_scheduling_enabled =
1347 settings.deadline_scheduling_enabled;
1329 scheduler_settings.impl_side_painting = settings.impl_side_painting; 1348 scheduler_settings.impl_side_painting = settings.impl_side_painting;
1330 scheduler_settings.timeout_and_draw_when_animation_checkerboards = 1349 scheduler_settings.timeout_and_draw_when_animation_checkerboards =
1331 settings.timeout_and_draw_when_animation_checkerboards; 1350 settings.timeout_and_draw_when_animation_checkerboards;
1332 scheduler_settings.maximum_number_of_failed_draws_before_draw_is_forced_ = 1351 scheduler_settings.maximum_number_of_failed_draws_before_draw_is_forced_ =
1333 settings.maximum_number_of_failed_draws_before_draw_is_forced_; 1352 settings.maximum_number_of_failed_draws_before_draw_is_forced_;
1334 scheduler_settings.using_synchronous_renderer_compositor = 1353 scheduler_settings.using_synchronous_renderer_compositor =
1335 settings.using_synchronous_renderer_compositor; 1354 settings.using_synchronous_renderer_compositor;
1336 scheduler_settings.throttle_frame_production = 1355 scheduler_settings.throttle_frame_production =
1337 settings.throttle_frame_production; 1356 settings.throttle_frame_production;
1338 scheduler_on_impl_thread_ = Scheduler::Create(this, scheduler_settings); 1357 scheduler_on_impl_thread_ = Scheduler::Create(this, scheduler_settings);
(...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after
1568 completion_event_for_commit_held_on_tree_activation_ = NULL; 1587 completion_event_for_commit_held_on_tree_activation_ = NULL;
1569 } 1588 }
1570 1589
1571 UpdateBackgroundAnimateTicking(); 1590 UpdateBackgroundAnimateTicking();
1572 1591
1573 commit_to_activate_duration_history_.InsertSample( 1592 commit_to_activate_duration_history_.InsertSample(
1574 base::TimeTicks::HighResNow() - commit_complete_time_); 1593 base::TimeTicks::HighResNow() - commit_complete_time_);
1575 } 1594 }
1576 1595
1577 } // namespace cc 1596 } // namespace cc
OLDNEW
« no previous file with comments | « cc/trees/thread_proxy.h ('k') | chrome/browser/chromeos/login/chrome_restart_request.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698