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
3 // found in the LICENSE file.
5 #include "cc/output/output_surface.h"
12 #include "base/bind.h"
13 #include "base/debug/trace_event.h"
14 #include "base/logging.h"
15 #include "base/message_loop/message_loop.h"
16 #include "base/metrics/histogram.h"
17 #include "base/strings/string_split.h"
18 #include "base/strings/string_util.h"
19 #include "cc/output/compositor_frame.h"
20 #include "cc/output/compositor_frame_ack.h"
21 #include "cc/output/managed_memory_policy.h"
22 #include "cc/output/output_surface_client.h"
23 #include "cc/scheduler/delay_based_time_source.h"
24 #include "gpu/GLES2/gl2extchromium.h"
25 #include "gpu/command_buffer/client/context_support.h"
26 #include "gpu/command_buffer/client/gles2_interface.h"
27 #include "third_party/khronos/GLES2/gl2.h"
28 #include "third_party/khronos/GLES2/gl2ext.h"
29 #include "ui/gfx/frame_time.h"
30 #include "ui/gfx/rect.h"
31 #include "ui/gfx/size.h"
39 const size_t kGpuLatencyHistorySize = 60;
40 const double kGpuLatencyEstimationPercentile = 100.0;
46 OutputSurface::OutputSurface(scoped_refptr<ContextProvider> context_provider)
47 : context_provider_(context_provider),
48 device_scale_factor_(-1),
49 max_frames_pending_(0),
50 pending_swap_buffers_(0),
51 needs_begin_impl_frame_(false),
52 client_ready_for_begin_impl_frame_(true),
54 check_for_retroactive_begin_impl_frame_pending_(false),
55 external_stencil_test_enabled_(false),
56 weak_ptr_factory_(this),
57 gpu_latency_history_(kGpuLatencyHistorySize) {}
59 OutputSurface::OutputSurface(scoped_ptr<SoftwareOutputDevice> software_device)
60 : software_device_(software_device.Pass()),
61 device_scale_factor_(-1),
62 max_frames_pending_(0),
63 pending_swap_buffers_(0),
64 needs_begin_impl_frame_(false),
65 client_ready_for_begin_impl_frame_(true),
67 check_for_retroactive_begin_impl_frame_pending_(false),
68 external_stencil_test_enabled_(false),
69 weak_ptr_factory_(this),
70 gpu_latency_history_(kGpuLatencyHistorySize) {}
72 OutputSurface::OutputSurface(scoped_refptr<ContextProvider> context_provider,
73 scoped_ptr<SoftwareOutputDevice> software_device)
74 : context_provider_(context_provider),
75 software_device_(software_device.Pass()),
76 device_scale_factor_(-1),
77 max_frames_pending_(0),
78 pending_swap_buffers_(0),
79 needs_begin_impl_frame_(false),
80 client_ready_for_begin_impl_frame_(true),
82 check_for_retroactive_begin_impl_frame_pending_(false),
83 external_stencil_test_enabled_(false),
84 weak_ptr_factory_(this),
85 gpu_latency_history_(kGpuLatencyHistorySize) {}
87 void OutputSurface::InitializeBeginImplFrameEmulation(
88 base::SingleThreadTaskRunner* task_runner,
89 bool throttle_frame_production,
90 base::TimeDelta interval) {
91 if (throttle_frame_production) {
92 scoped_refptr<DelayBasedTimeSource> time_source;
93 if (gfx::FrameTime::TimestampsAreHighRes())
94 time_source = DelayBasedTimeSourceHighRes::Create(interval, task_runner);
96 time_source = DelayBasedTimeSource::Create(interval, task_runner);
97 frame_rate_controller_.reset(new FrameRateController(time_source));
99 frame_rate_controller_.reset(new FrameRateController(task_runner));
102 frame_rate_controller_->SetClient(this);
103 frame_rate_controller_->SetMaxSwapsPending(max_frames_pending_);
104 frame_rate_controller_->SetDeadlineAdjustment(
105 capabilities_.adjust_deadline_for_parent ?
106 BeginFrameArgs::DefaultDeadlineAdjustment() : base::TimeDelta());
108 // The new frame rate controller will consume the swap acks of the old
109 // frame rate controller, so we set that expectation up here.
110 for (int i = 0; i < pending_swap_buffers_; i++)
111 frame_rate_controller_->DidSwapBuffers();
114 void OutputSurface::SetMaxFramesPending(int max_frames_pending) {
115 if (frame_rate_controller_)
116 frame_rate_controller_->SetMaxSwapsPending(max_frames_pending);
117 max_frames_pending_ = max_frames_pending;
120 void OutputSurface::CommitVSyncParameters(base::TimeTicks timebase,
121 base::TimeDelta interval) {
123 "OutputSurface::CommitVSyncParameters",
125 (timebase - base::TimeTicks()).InSecondsF(),
127 interval.InSecondsF());
128 if (frame_rate_controller_)
129 frame_rate_controller_->SetTimebaseAndInterval(timebase, interval);
132 void OutputSurface::FrameRateControllerTick(bool throttled,
133 const BeginFrameArgs& args) {
134 DCHECK(frame_rate_controller_);
136 skipped_begin_impl_frame_args_ = args;
138 BeginImplFrame(args);
141 // Forwarded to OutputSurfaceClient
142 void OutputSurface::SetNeedsRedrawRect(const gfx::Rect& damage_rect) {
143 TRACE_EVENT0("cc", "OutputSurface::SetNeedsRedrawRect");
144 client_->SetNeedsRedrawRect(damage_rect);
147 void OutputSurface::SetNeedsBeginImplFrame(bool enable) {
148 TRACE_EVENT1("cc", "OutputSurface::SetNeedsBeginImplFrame", "enable", enable);
149 needs_begin_impl_frame_ = enable;
150 client_ready_for_begin_impl_frame_ = true;
151 if (frame_rate_controller_) {
152 BeginFrameArgs skipped = frame_rate_controller_->SetActive(enable);
153 if (skipped.IsValid())
154 skipped_begin_impl_frame_args_ = skipped;
156 if (needs_begin_impl_frame_)
157 PostCheckForRetroactiveBeginImplFrame();
160 void OutputSurface::BeginImplFrame(const BeginFrameArgs& args) {
161 TRACE_EVENT2("cc", "OutputSurface::BeginImplFrame",
162 "client_ready_for_begin_impl_frame_",
163 client_ready_for_begin_impl_frame_,
164 "pending_swap_buffers_", pending_swap_buffers_);
165 if (!needs_begin_impl_frame_ || !client_ready_for_begin_impl_frame_ ||
166 (pending_swap_buffers_ >= max_frames_pending_ &&
167 max_frames_pending_ > 0)) {
168 skipped_begin_impl_frame_args_ = args;
170 client_ready_for_begin_impl_frame_ = false;
171 client_->BeginImplFrame(args);
172 // args might be an alias for skipped_begin_impl_frame_args_.
173 // Do not reset it before calling BeginImplFrame!
174 skipped_begin_impl_frame_args_ = BeginFrameArgs();
178 base::TimeTicks OutputSurface::RetroactiveBeginImplFrameDeadline() {
179 // TODO(brianderson): Remove the alternative deadline once we have better
180 // deadline estimations.
181 base::TimeTicks alternative_deadline =
182 skipped_begin_impl_frame_args_.frame_time +
183 BeginFrameArgs::DefaultRetroactiveBeginFramePeriod();
184 return std::max(skipped_begin_impl_frame_args_.deadline,
185 alternative_deadline);
188 void OutputSurface::PostCheckForRetroactiveBeginImplFrame() {
189 if (!skipped_begin_impl_frame_args_.IsValid() ||
190 check_for_retroactive_begin_impl_frame_pending_)
193 base::MessageLoop::current()->PostTask(
195 base::Bind(&OutputSurface::CheckForRetroactiveBeginImplFrame,
196 weak_ptr_factory_.GetWeakPtr()));
197 check_for_retroactive_begin_impl_frame_pending_ = true;
200 void OutputSurface::CheckForRetroactiveBeginImplFrame() {
201 TRACE_EVENT0("cc", "OutputSurface::CheckForRetroactiveBeginImplFrame");
202 check_for_retroactive_begin_impl_frame_pending_ = false;
203 if (gfx::FrameTime::Now() < RetroactiveBeginImplFrameDeadline())
204 BeginImplFrame(skipped_begin_impl_frame_args_);
207 void OutputSurface::DidSwapBuffers() {
208 pending_swap_buffers_++;
209 TRACE_EVENT1("cc", "OutputSurface::DidSwapBuffers",
210 "pending_swap_buffers_", pending_swap_buffers_);
211 client_->DidSwapBuffers();
212 if (frame_rate_controller_)
213 frame_rate_controller_->DidSwapBuffers();
214 PostCheckForRetroactiveBeginImplFrame();
217 void OutputSurface::OnSwapBuffersComplete() {
218 pending_swap_buffers_--;
219 TRACE_EVENT1("cc", "OutputSurface::OnSwapBuffersComplete",
220 "pending_swap_buffers_", pending_swap_buffers_);
221 client_->OnSwapBuffersComplete();
222 if (frame_rate_controller_)
223 frame_rate_controller_->DidSwapBuffersComplete();
224 PostCheckForRetroactiveBeginImplFrame();
227 void OutputSurface::ReclaimResources(const CompositorFrameAck* ack) {
228 client_->ReclaimResources(ack);
231 void OutputSurface::DidLoseOutputSurface() {
232 TRACE_EVENT0("cc", "OutputSurface::DidLoseOutputSurface");
233 client_ready_for_begin_impl_frame_ = true;
234 pending_swap_buffers_ = 0;
235 skipped_begin_impl_frame_args_ = BeginFrameArgs();
236 if (frame_rate_controller_)
237 frame_rate_controller_->SetActive(false);
238 pending_gpu_latency_query_ids_.clear();
239 available_gpu_latency_query_ids_.clear();
240 client_->DidLoseOutputSurface();
243 void OutputSurface::SetExternalStencilTest(bool enabled) {
244 external_stencil_test_enabled_ = enabled;
247 void OutputSurface::SetExternalDrawConstraints(const gfx::Transform& transform,
248 const gfx::Rect& viewport,
249 const gfx::Rect& clip,
250 bool valid_for_tile_management) {
251 client_->SetExternalDrawConstraints(
252 transform, viewport, clip, valid_for_tile_management);
255 OutputSurface::~OutputSurface() {
256 if (frame_rate_controller_)
257 frame_rate_controller_->SetActive(false);
261 bool OutputSurface::HasExternalStencilTest() const {
262 return external_stencil_test_enabled_;
265 bool OutputSurface::ForcedDrawToSoftwareDevice() const { return false; }
267 bool OutputSurface::BindToClient(OutputSurfaceClient* client) {
272 if (context_provider_) {
273 success = context_provider_->BindToCurrentThread();
284 bool OutputSurface::InitializeAndSetContext3d(
285 scoped_refptr<ContextProvider> context_provider,
286 scoped_refptr<ContextProvider> offscreen_context_provider) {
287 DCHECK(!context_provider_);
288 DCHECK(context_provider);
291 bool success = false;
292 if (context_provider->BindToCurrentThread()) {
293 context_provider_ = context_provider;
295 if (client_->DeferredInitialize(offscreen_context_provider))
305 void OutputSurface::ReleaseGL() {
307 DCHECK(context_provider_);
308 client_->ReleaseGL();
312 void OutputSurface::SetUpContext3d() {
313 DCHECK(context_provider_);
316 context_provider_->SetLostContextCallback(
317 base::Bind(&OutputSurface::DidLoseOutputSurface,
318 base::Unretained(this)));
319 context_provider_->ContextSupport()->SetSwapBuffersCompleteCallback(
320 base::Bind(&OutputSurface::OnSwapBuffersComplete,
321 base::Unretained(this)));
322 context_provider_->SetMemoryPolicyChangedCallback(
323 base::Bind(&OutputSurface::SetMemoryPolicy,
324 base::Unretained(this)));
327 void OutputSurface::ResetContext3d() {
328 if (context_provider_.get()) {
329 while (!pending_gpu_latency_query_ids_.empty()) {
330 unsigned query_id = pending_gpu_latency_query_ids_.front();
331 pending_gpu_latency_query_ids_.pop_front();
332 context_provider_->ContextGL()->DeleteQueriesEXT(1, &query_id);
334 while (!available_gpu_latency_query_ids_.empty()) {
335 unsigned query_id = available_gpu_latency_query_ids_.front();
336 available_gpu_latency_query_ids_.pop_front();
337 context_provider_->ContextGL()->DeleteQueriesEXT(1, &query_id);
339 context_provider_->SetLostContextCallback(
340 ContextProvider::LostContextCallback());
341 context_provider_->SetMemoryPolicyChangedCallback(
342 ContextProvider::MemoryPolicyChangedCallback());
343 if (gpu::ContextSupport* support = context_provider_->ContextSupport())
344 support->SetSwapBuffersCompleteCallback(base::Closure());
346 context_provider_ = NULL;
349 void OutputSurface::EnsureBackbuffer() {
350 if (software_device_)
351 software_device_->EnsureBackbuffer();
354 void OutputSurface::DiscardBackbuffer() {
355 if (context_provider_)
356 context_provider_->ContextGL()->DiscardBackbufferCHROMIUM();
357 if (software_device_)
358 software_device_->DiscardBackbuffer();
361 void OutputSurface::Reshape(const gfx::Size& size, float scale_factor) {
362 if (size == surface_size_ && scale_factor == device_scale_factor_)
365 surface_size_ = size;
366 device_scale_factor_ = scale_factor;
367 if (context_provider_) {
368 context_provider_->ContextGL()->ResizeCHROMIUM(
369 size.width(), size.height(), scale_factor);
371 if (software_device_)
372 software_device_->Resize(size);
375 gfx::Size OutputSurface::SurfaceSize() const {
376 return surface_size_;
379 void OutputSurface::BindFramebuffer() {
380 DCHECK(context_provider_);
381 context_provider_->ContextGL()->BindFramebuffer(GL_FRAMEBUFFER, 0);
384 void OutputSurface::SwapBuffers(CompositorFrame* frame) {
385 if (frame->software_frame_data) {
386 PostSwapBuffersComplete();
391 DCHECK(context_provider_);
392 DCHECK(frame->gl_frame_data);
394 UpdateAndMeasureGpuLatency();
395 if (frame->gl_frame_data->sub_buffer_rect ==
396 gfx::Rect(frame->gl_frame_data->size)) {
397 context_provider_->ContextSupport()->Swap();
399 context_provider_->ContextSupport()->PartialSwapBuffers(
400 frame->gl_frame_data->sub_buffer_rect);
406 base::TimeDelta OutputSurface::GpuLatencyEstimate() {
407 if (context_provider_ && !capabilities_.adjust_deadline_for_parent)
408 return gpu_latency_history_.Percentile(kGpuLatencyEstimationPercentile);
410 return base::TimeDelta();
413 void OutputSurface::UpdateAndMeasureGpuLatency() {
414 return; // http://crbug.com/306690 tracks re-enabling latency queries.
416 // We only care about GPU latency for surfaces that do not have a parent
417 // compositor, since surfaces that do have a parent compositor can use
418 // mailboxes or delegated rendering to send frames to their parent without
419 // incurring GPU latency.
420 if (capabilities_.adjust_deadline_for_parent)
423 while (pending_gpu_latency_query_ids_.size()) {
424 unsigned query_id = pending_gpu_latency_query_ids_.front();
425 unsigned query_complete = 1;
426 context_provider_->ContextGL()->GetQueryObjectuivEXT(
427 query_id, GL_QUERY_RESULT_AVAILABLE_EXT, &query_complete);
432 context_provider_->ContextGL()->GetQueryObjectuivEXT(
433 query_id, GL_QUERY_RESULT_EXT, &value);
434 pending_gpu_latency_query_ids_.pop_front();
435 available_gpu_latency_query_ids_.push_back(query_id);
437 base::TimeDelta latency = base::TimeDelta::FromMicroseconds(value);
438 base::TimeDelta latency_estimate = GpuLatencyEstimate();
439 gpu_latency_history_.InsertSample(latency);
441 base::TimeDelta latency_overestimate;
442 base::TimeDelta latency_underestimate;
443 if (latency > latency_estimate)
444 latency_underestimate = latency - latency_estimate;
446 latency_overestimate = latency_estimate - latency;
447 UMA_HISTOGRAM_CUSTOM_TIMES("Renderer.GpuLatency",
449 base::TimeDelta::FromMilliseconds(1),
450 base::TimeDelta::FromMilliseconds(100),
452 UMA_HISTOGRAM_CUSTOM_TIMES("Renderer.GpuLatencyUnderestimate",
453 latency_underestimate,
454 base::TimeDelta::FromMilliseconds(1),
455 base::TimeDelta::FromMilliseconds(100),
457 UMA_HISTOGRAM_CUSTOM_TIMES("Renderer.GpuLatencyOverestimate",
458 latency_overestimate,
459 base::TimeDelta::FromMilliseconds(1),
460 base::TimeDelta::FromMilliseconds(100),
464 unsigned gpu_latency_query_id;
465 if (available_gpu_latency_query_ids_.size()) {
466 gpu_latency_query_id = available_gpu_latency_query_ids_.front();
467 available_gpu_latency_query_ids_.pop_front();
469 context_provider_->ContextGL()->GenQueriesEXT(1, &gpu_latency_query_id);
472 context_provider_->ContextGL()->BeginQueryEXT(GL_LATENCY_QUERY_CHROMIUM,
473 gpu_latency_query_id);
474 context_provider_->ContextGL()->EndQueryEXT(GL_LATENCY_QUERY_CHROMIUM);
475 pending_gpu_latency_query_ids_.push_back(gpu_latency_query_id);
478 void OutputSurface::PostSwapBuffersComplete() {
479 base::MessageLoop::current()->PostTask(
481 base::Bind(&OutputSurface::OnSwapBuffersComplete,
482 weak_ptr_factory_.GetWeakPtr()));
485 void OutputSurface::SetMemoryPolicy(const ManagedMemoryPolicy& policy) {
486 TRACE_EVENT1("cc", "OutputSurface::SetMemoryPolicy",
487 "bytes_limit_when_visible", policy.bytes_limit_when_visible);
488 // Just ignore the memory manager when it says to set the limit to zero
489 // bytes. This will happen when the memory manager thinks that the renderer
490 // is not visible (which the renderer knows better).
491 if (policy.bytes_limit_when_visible)
492 client_->SetMemoryPolicy(policy);