Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 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/output/output_surface.h" | 5 #include "cc/output/output_surface.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <set> | 8 #include <set> |
| 9 #include <string> | 9 #include <string> |
| 10 #include <vector> | 10 #include <vector> |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 37 namespace { | 37 namespace { |
| 38 | 38 |
| 39 const size_t kGpuLatencyHistorySize = 60; | 39 const size_t kGpuLatencyHistorySize = 60; |
| 40 const double kGpuLatencyEstimationPercentile = 100.0; | 40 const double kGpuLatencyEstimationPercentile = 100.0; |
| 41 | 41 |
| 42 } | 42 } |
| 43 | 43 |
| 44 namespace cc { | 44 namespace cc { |
| 45 | 45 |
| 46 OutputSurface::OutputSurface(scoped_refptr<ContextProvider> context_provider) | 46 OutputSurface::OutputSurface(scoped_refptr<ContextProvider> context_provider) |
| 47 : context_provider_(context_provider), | 47 : client_(NULL), |
| 48 is_lost_(false), | |
| 49 context_provider_(context_provider), | |
| 48 device_scale_factor_(-1), | 50 device_scale_factor_(-1), |
| 49 begin_frame_interval_(BeginFrameArgs::DefaultInterval()), | |
| 50 throttle_frame_production_(true), | |
| 51 needs_begin_frame_(false), | |
| 52 client_ready_for_begin_frame_(true), | |
| 53 client_(NULL), | |
| 54 is_lost_(false), | |
| 55 check_for_retroactive_begin_frame_pending_(false), | |
| 56 external_stencil_test_enabled_(false), | 51 external_stencil_test_enabled_(false), |
| 57 weak_ptr_factory_(this), | 52 weak_ptr_factory_(this), |
| 58 gpu_latency_history_(kGpuLatencyHistorySize) {} | 53 gpu_latency_history_(kGpuLatencyHistorySize) {} |
| 59 | 54 |
| 60 OutputSurface::OutputSurface(scoped_ptr<SoftwareOutputDevice> software_device) | 55 OutputSurface::OutputSurface(scoped_ptr<SoftwareOutputDevice> software_device) |
| 61 : software_device_(software_device.Pass()), | 56 : client_(NULL), |
| 57 is_lost_(false), | |
| 58 software_device_(software_device.Pass()), | |
| 62 device_scale_factor_(-1), | 59 device_scale_factor_(-1), |
| 63 begin_frame_interval_(BeginFrameArgs::DefaultInterval()), | |
| 64 throttle_frame_production_(true), | |
| 65 needs_begin_frame_(false), | |
| 66 client_ready_for_begin_frame_(true), | |
| 67 client_(NULL), | |
| 68 is_lost_(false), | |
| 69 check_for_retroactive_begin_frame_pending_(false), | |
| 70 external_stencil_test_enabled_(false), | 60 external_stencil_test_enabled_(false), |
| 71 weak_ptr_factory_(this), | 61 weak_ptr_factory_(this), |
| 72 gpu_latency_history_(kGpuLatencyHistorySize) {} | 62 gpu_latency_history_(kGpuLatencyHistorySize) {} |
| 73 | 63 |
| 74 OutputSurface::OutputSurface(scoped_refptr<ContextProvider> context_provider, | 64 OutputSurface::OutputSurface(scoped_refptr<ContextProvider> context_provider, |
| 75 scoped_ptr<SoftwareOutputDevice> software_device) | 65 scoped_ptr<SoftwareOutputDevice> software_device) |
| 76 : context_provider_(context_provider), | 66 : client_(NULL), |
| 67 is_lost_(false), | |
| 68 context_provider_(context_provider), | |
| 77 software_device_(software_device.Pass()), | 69 software_device_(software_device.Pass()), |
| 78 device_scale_factor_(-1), | 70 device_scale_factor_(-1), |
| 79 begin_frame_interval_(BeginFrameArgs::DefaultInterval()), | |
| 80 throttle_frame_production_(true), | |
| 81 needs_begin_frame_(false), | |
| 82 client_ready_for_begin_frame_(true), | |
| 83 client_(NULL), | |
| 84 is_lost_(false), | |
| 85 check_for_retroactive_begin_frame_pending_(false), | |
| 86 external_stencil_test_enabled_(false), | 71 external_stencil_test_enabled_(false), |
| 87 weak_ptr_factory_(this), | 72 weak_ptr_factory_(this), |
| 88 gpu_latency_history_(kGpuLatencyHistorySize) {} | 73 gpu_latency_history_(kGpuLatencyHistorySize) {} |
| 89 | 74 |
| 90 void OutputSurface::SetThrottleFrameProduction(bool enable) { | |
| 91 DCHECK(!frame_rate_controller_); | |
| 92 throttle_frame_production_ = enable; | |
| 93 } | |
| 94 | |
| 95 void OutputSurface::InitializeBeginFrameEmulation( | |
| 96 base::SingleThreadTaskRunner* task_runner, | |
| 97 base::TimeDelta interval) { | |
| 98 DCHECK(throttle_frame_production_); | |
| 99 scoped_refptr<DelayBasedTimeSource> time_source; | |
| 100 if (gfx::FrameTime::TimestampsAreHighRes()) | |
| 101 time_source = DelayBasedTimeSourceHighRes::Create(interval, task_runner); | |
| 102 else | |
| 103 time_source = DelayBasedTimeSource::Create(interval, task_runner); | |
| 104 frame_rate_controller_.reset(new FrameRateController(time_source)); | |
| 105 | |
| 106 frame_rate_controller_->SetClient(this); | |
| 107 frame_rate_controller_->SetDeadlineAdjustment( | |
| 108 capabilities_.adjust_deadline_for_parent ? | |
| 109 BeginFrameArgs::DefaultDeadlineAdjustment() : base::TimeDelta()); | |
| 110 } | |
| 111 | |
| 112 void OutputSurface::CommitVSyncParameters(base::TimeTicks timebase, | 75 void OutputSurface::CommitVSyncParameters(base::TimeTicks timebase, |
| 113 base::TimeDelta interval) { | 76 base::TimeDelta interval) { |
| 114 TRACE_EVENT2("cc", | 77 TRACE_EVENT2("cc", |
| 115 "OutputSurface::CommitVSyncParameters", | 78 "OutputSurface::CommitVSyncParameters", |
| 116 "timebase", | 79 "timebase", |
| 117 (timebase - base::TimeTicks()).InSecondsF(), | 80 (timebase - base::TimeTicks()).InSecondsF(), |
| 118 "interval", | 81 "interval", |
| 119 interval.InSecondsF()); | 82 interval.InSecondsF()); |
| 120 begin_frame_interval_ = interval; | 83 client_->CommitVSyncParameters(timebase, interval); |
| 121 if (frame_rate_controller_) | |
| 122 frame_rate_controller_->SetTimebaseAndInterval(timebase, interval); | |
| 123 } | |
| 124 | |
| 125 void OutputSurface::FrameRateControllerTick(const BeginFrameArgs& args) { | |
| 126 DCHECK(frame_rate_controller_); | |
| 127 BeginFrame(args); | |
| 128 } | |
| 129 | |
| 130 // Forwarded to OutputSurfaceClient | |
| 131 void OutputSurface::SetNeedsRedrawRect(const gfx::Rect& damage_rect) { | |
| 132 TRACE_EVENT0("cc", "OutputSurface::SetNeedsRedrawRect"); | |
| 133 client_->SetNeedsRedrawRect(damage_rect); | |
| 134 } | |
| 135 | |
| 136 void OutputSurface::SetNeedsBeginFrame(bool enable) { | |
| 137 TRACE_EVENT1("cc", "OutputSurface::SetNeedsBeginFrame", "enable", enable); | |
| 138 needs_begin_frame_ = enable; | |
| 139 client_ready_for_begin_frame_ = true; | |
| 140 if (!throttle_frame_production_) { | |
| 141 if (enable) { | |
| 142 base::TimeTicks frame_time = gfx::FrameTime::Now(); | |
| 143 base::TimeTicks deadline = frame_time + begin_frame_interval_; | |
| 144 skipped_begin_frame_args_ = | |
| 145 BeginFrameArgs::Create(frame_time, deadline, begin_frame_interval_); | |
| 146 } | |
| 147 } else if (frame_rate_controller_) { | |
| 148 BeginFrameArgs skipped = frame_rate_controller_->SetActive(enable); | |
| 149 if (skipped.IsValid()) | |
| 150 skipped_begin_frame_args_ = skipped; | |
| 151 } | |
| 152 | |
| 153 if (needs_begin_frame_) | |
| 154 PostCheckForRetroactiveBeginFrame(); | |
| 155 } | |
| 156 | |
| 157 void OutputSurface::BeginFrame(const BeginFrameArgs& args) { | |
| 158 TRACE_EVENT1("cc", | |
| 159 "OutputSurface::BeginFrame", | |
| 160 "client_ready_for_begin_frame_", | |
| 161 client_ready_for_begin_frame_); | |
| 162 if (!needs_begin_frame_ || !client_ready_for_begin_frame_) { | |
| 163 skipped_begin_frame_args_ = args; | |
| 164 } else { | |
| 165 client_ready_for_begin_frame_ = false; | |
| 166 client_->BeginFrame(args); | |
| 167 // args might be an alias for skipped_begin_frame_args_. | |
| 168 // Do not reset it before calling BeginFrame! | |
| 169 skipped_begin_frame_args_ = BeginFrameArgs(); | |
| 170 } | |
| 171 } | |
| 172 | |
| 173 base::TimeTicks OutputSurface::RetroactiveBeginFrameDeadline() { | |
| 174 // TODO(brianderson): Remove the alternative deadline once we have better | |
| 175 // deadline estimations. | |
| 176 base::TimeTicks alternative_deadline = | |
| 177 skipped_begin_frame_args_.frame_time + | |
| 178 BeginFrameArgs::DefaultRetroactiveBeginFramePeriod(); | |
| 179 return std::max(skipped_begin_frame_args_.deadline, alternative_deadline); | |
| 180 } | |
| 181 | |
| 182 void OutputSurface::PostCheckForRetroactiveBeginFrame() { | |
| 183 if (!skipped_begin_frame_args_.IsValid() || | |
| 184 check_for_retroactive_begin_frame_pending_) | |
| 185 return; | |
| 186 | |
| 187 base::MessageLoop::current()->PostTask( | |
| 188 FROM_HERE, | |
| 189 base::Bind(&OutputSurface::CheckForRetroactiveBeginFrame, | |
| 190 weak_ptr_factory_.GetWeakPtr())); | |
| 191 check_for_retroactive_begin_frame_pending_ = true; | |
| 192 } | |
| 193 | |
| 194 void OutputSurface::CheckForRetroactiveBeginFrame() { | |
| 195 TRACE_EVENT0("cc", "OutputSurface::CheckForRetroactiveBeginFrame"); | |
| 196 check_for_retroactive_begin_frame_pending_ = false; | |
| 197 if (!throttle_frame_production_ || | |
| 198 gfx::FrameTime::Now() < RetroactiveBeginFrameDeadline()) | |
| 199 BeginFrame(skipped_begin_frame_args_); | |
| 200 } | |
| 201 | |
| 202 void OutputSurface::DidSwapBuffers() { | |
| 203 if (is_lost_) | |
| 204 return; | |
| 205 TRACE_EVENT0("cc", "OutputSurface::DidSwapBuffers"); | |
| 206 client_->DidSwapBuffers(); | |
| 207 } | |
| 208 | |
| 209 void OutputSurface::OnSwapBuffersComplete() { | |
| 210 if (is_lost_) | |
| 211 return; | |
| 212 TRACE_EVENT0("cc", "OutputSurface::OnSwapBuffersComplete"); | |
| 213 client_->OnSwapBuffersComplete(); | |
| 214 } | 84 } |
| 215 | 85 |
| 216 void OutputSurface::ReclaimResources(const CompositorFrameAck* ack) { | 86 void OutputSurface::ReclaimResources(const CompositorFrameAck* ack) { |
| 217 client_->ReclaimResources(ack); | 87 client_->ReclaimResources(ack); |
| 218 } | 88 } |
| 219 | 89 |
| 220 void OutputSurface::DidLoseOutputSurface() { | 90 void OutputSurface::DidLoseOutputSurface() { |
| 221 TRACE_EVENT0("cc", "OutputSurface::DidLoseOutputSurface"); | 91 TRACE_EVENT0("cc", "OutputSurface::DidLoseOutputSurface"); |
| 222 client_ready_for_begin_frame_ = true; | 92 is_lost_ = true; |
| 223 skipped_begin_frame_args_ = BeginFrameArgs(); | |
| 224 if (frame_rate_controller_) | |
| 225 frame_rate_controller_->SetActive(false); | |
| 226 pending_gpu_latency_query_ids_.clear(); | 93 pending_gpu_latency_query_ids_.clear(); |
| 227 available_gpu_latency_query_ids_.clear(); | 94 available_gpu_latency_query_ids_.clear(); |
| 228 client_->DidLoseOutputSurface(); | 95 client_->DidLoseOutputSurface(); |
| 229 is_lost_ = true; | |
| 230 } | 96 } |
| 231 | 97 |
| 232 void OutputSurface::SetExternalStencilTest(bool enabled) { | 98 void OutputSurface::SetExternalStencilTest(bool enabled) { |
| 233 external_stencil_test_enabled_ = enabled; | 99 external_stencil_test_enabled_ = enabled; |
| 234 } | 100 } |
| 235 | 101 |
| 236 void OutputSurface::SetExternalDrawConstraints(const gfx::Transform& transform, | 102 void OutputSurface::SetExternalDrawConstraints(const gfx::Transform& transform, |
| 237 const gfx::Rect& viewport, | 103 const gfx::Rect& viewport, |
| 238 const gfx::Rect& clip, | 104 const gfx::Rect& clip, |
| 239 bool valid_for_tile_management) { | 105 bool valid_for_tile_management) { |
| 240 client_->SetExternalDrawConstraints( | 106 client_->SetExternalDrawConstraints( |
| 241 transform, viewport, clip, valid_for_tile_management); | 107 transform, viewport, clip, valid_for_tile_management); |
| 242 } | 108 } |
| 243 | 109 |
| 244 OutputSurface::~OutputSurface() { | 110 OutputSurface::~OutputSurface() { |
| 245 if (frame_rate_controller_) | |
| 246 frame_rate_controller_->SetActive(false); | |
| 247 ResetContext3d(); | 111 ResetContext3d(); |
| 248 } | 112 } |
| 249 | 113 |
| 250 bool OutputSurface::HasExternalStencilTest() const { | 114 bool OutputSurface::HasExternalStencilTest() const { |
| 251 return external_stencil_test_enabled_; | 115 return external_stencil_test_enabled_; |
| 252 } | 116 } |
| 253 | 117 |
| 254 bool OutputSurface::ForcedDrawToSoftwareDevice() const { return false; } | 118 bool OutputSurface::ForcedDrawToSoftwareDevice() const { return false; } |
| 255 | 119 |
| 256 bool OutputSurface::BindToClient(OutputSurfaceClient* client) { | 120 bool OutputSurface::BindToClient(OutputSurfaceClient* client) { |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 366 } | 230 } |
| 367 | 231 |
| 368 void OutputSurface::BindFramebuffer() { | 232 void OutputSurface::BindFramebuffer() { |
| 369 DCHECK(context_provider_); | 233 DCHECK(context_provider_); |
| 370 context_provider_->ContextGL()->BindFramebuffer(GL_FRAMEBUFFER, 0); | 234 context_provider_->ContextGL()->BindFramebuffer(GL_FRAMEBUFFER, 0); |
| 371 } | 235 } |
| 372 | 236 |
| 373 void OutputSurface::SwapBuffers(CompositorFrame* frame) { | 237 void OutputSurface::SwapBuffers(CompositorFrame* frame) { |
| 374 if (frame->software_frame_data) { | 238 if (frame->software_frame_data) { |
| 375 PostSwapBuffersComplete(); | 239 PostSwapBuffersComplete(); |
| 376 DidSwapBuffers(); | 240 client_->DidSwapBuffers(); |
| 377 return; | 241 return; |
| 378 } | 242 } |
| 379 | 243 |
| 380 DCHECK(context_provider_); | 244 DCHECK(context_provider_); |
| 381 DCHECK(frame->gl_frame_data); | 245 DCHECK(frame->gl_frame_data); |
| 382 | 246 |
| 383 UpdateAndMeasureGpuLatency(); | 247 UpdateAndMeasureGpuLatency(); |
| 384 if (frame->gl_frame_data->sub_buffer_rect == | 248 if (frame->gl_frame_data->sub_buffer_rect == |
| 385 gfx::Rect(frame->gl_frame_data->size)) { | 249 gfx::Rect(frame->gl_frame_data->size)) { |
| 386 context_provider_->ContextSupport()->Swap(); | 250 context_provider_->ContextSupport()->Swap(); |
| 387 } else { | 251 } else { |
| 388 context_provider_->ContextSupport()->PartialSwapBuffers( | 252 context_provider_->ContextSupport()->PartialSwapBuffers( |
| 389 frame->gl_frame_data->sub_buffer_rect); | 253 frame->gl_frame_data->sub_buffer_rect); |
| 390 } | 254 } |
| 391 | 255 |
| 392 DidSwapBuffers(); | 256 client_->DidSwapBuffers(); |
|
Sami
2014/04/08 13:46:01
Should we guard against is_lost_?
brianderson
2014/04/09 02:52:05
Good idea. I will return early if is_lost_ here an
brianderson
2014/04/10 23:45:58
Done.
| |
| 393 } | 257 } |
| 394 | 258 |
| 395 base::TimeDelta OutputSurface::GpuLatencyEstimate() { | 259 base::TimeDelta OutputSurface::GpuLatencyEstimate() { |
| 396 if (context_provider_ && !capabilities_.adjust_deadline_for_parent) | 260 if (context_provider_ && !capabilities_.adjust_deadline_for_parent) |
| 397 return gpu_latency_history_.Percentile(kGpuLatencyEstimationPercentile); | 261 return gpu_latency_history_.Percentile(kGpuLatencyEstimationPercentile); |
| 398 else | 262 else |
| 399 return base::TimeDelta(); | 263 return base::TimeDelta(); |
| 400 } | 264 } |
| 401 | 265 |
| 402 void OutputSurface::UpdateAndMeasureGpuLatency() { | 266 void OutputSurface::UpdateAndMeasureGpuLatency() { |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 465 #endif | 329 #endif |
| 466 } | 330 } |
| 467 | 331 |
| 468 void OutputSurface::PostSwapBuffersComplete() { | 332 void OutputSurface::PostSwapBuffersComplete() { |
| 469 base::MessageLoop::current()->PostTask( | 333 base::MessageLoop::current()->PostTask( |
| 470 FROM_HERE, | 334 FROM_HERE, |
| 471 base::Bind(&OutputSurface::OnSwapBuffersComplete, | 335 base::Bind(&OutputSurface::OnSwapBuffersComplete, |
| 472 weak_ptr_factory_.GetWeakPtr())); | 336 weak_ptr_factory_.GetWeakPtr())); |
| 473 } | 337 } |
| 474 | 338 |
| 339 void OutputSurface::OnSwapBuffersComplete() { | |
| 340 if (!is_lost_) | |
| 341 client_->OnSwapBuffersComplete(); | |
| 342 } | |
| 343 | |
| 475 void OutputSurface::SetMemoryPolicy(const ManagedMemoryPolicy& policy) { | 344 void OutputSurface::SetMemoryPolicy(const ManagedMemoryPolicy& policy) { |
| 476 TRACE_EVENT1("cc", "OutputSurface::SetMemoryPolicy", | 345 TRACE_EVENT1("cc", "OutputSurface::SetMemoryPolicy", |
| 477 "bytes_limit_when_visible", policy.bytes_limit_when_visible); | 346 "bytes_limit_when_visible", policy.bytes_limit_when_visible); |
| 478 // Just ignore the memory manager when it says to set the limit to zero | 347 // Just ignore the memory manager when it says to set the limit to zero |
| 479 // bytes. This will happen when the memory manager thinks that the renderer | 348 // bytes. This will happen when the memory manager thinks that the renderer |
| 480 // is not visible (which the renderer knows better). | 349 // is not visible (which the renderer knows better). |
| 481 if (policy.bytes_limit_when_visible) | 350 if (policy.bytes_limit_when_visible) |
| 482 client_->SetMemoryPolicy(policy); | 351 client_->SetMemoryPolicy(policy); |
| 483 } | 352 } |
| 484 | 353 |
| 485 } // namespace cc | 354 } // namespace cc |
| OLD | NEW |