• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "cc/output/output_surface.h"
6 
7 #include <algorithm>
8 #include <set>
9 #include <string>
10 #include <vector>
11 
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/WebKit/public/platform/WebGraphicsContext3D.h"
28 #include "third_party/khronos/GLES2/gl2.h"
29 #include "third_party/khronos/GLES2/gl2ext.h"
30 #include "ui/gfx/frame_time.h"
31 #include "ui/gfx/rect.h"
32 #include "ui/gfx/size.h"
33 
34 using std::set;
35 using std::string;
36 using std::vector;
37 
38 namespace {
39 
40 const size_t kGpuLatencyHistorySize = 60;
41 const double kGpuLatencyEstimationPercentile = 100.0;
42 
43 }
44 
45 namespace cc {
46 
OutputSurface(scoped_refptr<ContextProvider> context_provider)47 OutputSurface::OutputSurface(scoped_refptr<ContextProvider> context_provider)
48     : context_provider_(context_provider),
49       device_scale_factor_(-1),
50       max_frames_pending_(0),
51       pending_swap_buffers_(0),
52       needs_begin_impl_frame_(false),
53       client_ready_for_begin_impl_frame_(true),
54       client_(NULL),
55       check_for_retroactive_begin_impl_frame_pending_(false),
56       external_stencil_test_enabled_(false),
57       weak_ptr_factory_(this),
58       gpu_latency_history_(kGpuLatencyHistorySize) {}
59 
OutputSurface(scoped_ptr<SoftwareOutputDevice> software_device)60 OutputSurface::OutputSurface(scoped_ptr<SoftwareOutputDevice> software_device)
61     : software_device_(software_device.Pass()),
62       device_scale_factor_(-1),
63       max_frames_pending_(0),
64       pending_swap_buffers_(0),
65       needs_begin_impl_frame_(false),
66       client_ready_for_begin_impl_frame_(true),
67       client_(NULL),
68       check_for_retroactive_begin_impl_frame_pending_(false),
69       external_stencil_test_enabled_(false),
70       weak_ptr_factory_(this),
71       gpu_latency_history_(kGpuLatencyHistorySize) {}
72 
OutputSurface(scoped_refptr<ContextProvider> context_provider,scoped_ptr<SoftwareOutputDevice> software_device)73 OutputSurface::OutputSurface(scoped_refptr<ContextProvider> context_provider,
74                              scoped_ptr<SoftwareOutputDevice> software_device)
75     : context_provider_(context_provider),
76       software_device_(software_device.Pass()),
77       device_scale_factor_(-1),
78       max_frames_pending_(0),
79       pending_swap_buffers_(0),
80       needs_begin_impl_frame_(false),
81       client_ready_for_begin_impl_frame_(true),
82       client_(NULL),
83       check_for_retroactive_begin_impl_frame_pending_(false),
84       external_stencil_test_enabled_(false),
85       weak_ptr_factory_(this),
86       gpu_latency_history_(kGpuLatencyHistorySize) {}
87 
InitializeBeginImplFrameEmulation(base::SingleThreadTaskRunner * task_runner,bool throttle_frame_production,base::TimeDelta interval)88 void OutputSurface::InitializeBeginImplFrameEmulation(
89     base::SingleThreadTaskRunner* task_runner,
90     bool throttle_frame_production,
91     base::TimeDelta interval) {
92   if (throttle_frame_production) {
93     scoped_refptr<DelayBasedTimeSource> time_source;
94     if (gfx::FrameTime::TimestampsAreHighRes())
95       time_source = DelayBasedTimeSourceHighRes::Create(interval, task_runner);
96     else
97       time_source = DelayBasedTimeSource::Create(interval, task_runner);
98     frame_rate_controller_.reset(new FrameRateController(time_source));
99   } else {
100     frame_rate_controller_.reset(new FrameRateController(task_runner));
101   }
102 
103   frame_rate_controller_->SetClient(this);
104   frame_rate_controller_->SetMaxSwapsPending(max_frames_pending_);
105   frame_rate_controller_->SetDeadlineAdjustment(
106       capabilities_.adjust_deadline_for_parent ?
107           BeginFrameArgs::DefaultDeadlineAdjustment() : base::TimeDelta());
108 
109   // The new frame rate controller will consume the swap acks of the old
110   // frame rate controller, so we set that expectation up here.
111   for (int i = 0; i < pending_swap_buffers_; i++)
112     frame_rate_controller_->DidSwapBuffers();
113 }
114 
SetMaxFramesPending(int max_frames_pending)115 void OutputSurface::SetMaxFramesPending(int max_frames_pending) {
116   if (frame_rate_controller_)
117     frame_rate_controller_->SetMaxSwapsPending(max_frames_pending);
118   max_frames_pending_ = max_frames_pending;
119 }
120 
OnVSyncParametersChanged(base::TimeTicks timebase,base::TimeDelta interval)121 void OutputSurface::OnVSyncParametersChanged(base::TimeTicks timebase,
122                                              base::TimeDelta interval) {
123   TRACE_EVENT2("cc", "OutputSurface::OnVSyncParametersChanged",
124                "timebase", (timebase - base::TimeTicks()).InSecondsF(),
125                "interval", interval.InSecondsF());
126   if (frame_rate_controller_)
127     frame_rate_controller_->SetTimebaseAndInterval(timebase, interval);
128 }
129 
FrameRateControllerTick(bool throttled,const BeginFrameArgs & args)130 void OutputSurface::FrameRateControllerTick(bool throttled,
131                                             const BeginFrameArgs& args) {
132   DCHECK(frame_rate_controller_);
133   if (throttled)
134     skipped_begin_impl_frame_args_ = args;
135   else
136     BeginImplFrame(args);
137 }
138 
139 // Forwarded to OutputSurfaceClient
SetNeedsRedrawRect(gfx::Rect damage_rect)140 void OutputSurface::SetNeedsRedrawRect(gfx::Rect damage_rect) {
141   TRACE_EVENT0("cc", "OutputSurface::SetNeedsRedrawRect");
142   client_->SetNeedsRedrawRect(damage_rect);
143 }
144 
SetNeedsBeginImplFrame(bool enable)145 void OutputSurface::SetNeedsBeginImplFrame(bool enable) {
146   TRACE_EVENT1("cc", "OutputSurface::SetNeedsBeginImplFrame", "enable", enable);
147   needs_begin_impl_frame_ = enable;
148   client_ready_for_begin_impl_frame_ = true;
149   if (frame_rate_controller_) {
150     BeginFrameArgs skipped = frame_rate_controller_->SetActive(enable);
151     if (skipped.IsValid())
152       skipped_begin_impl_frame_args_ = skipped;
153   }
154   if (needs_begin_impl_frame_)
155     PostCheckForRetroactiveBeginImplFrame();
156 }
157 
BeginImplFrame(const BeginFrameArgs & args)158 void OutputSurface::BeginImplFrame(const BeginFrameArgs& args) {
159   TRACE_EVENT2("cc", "OutputSurface::BeginImplFrame",
160                "client_ready_for_begin_impl_frame_",
161                client_ready_for_begin_impl_frame_,
162                "pending_swap_buffers_", pending_swap_buffers_);
163   if (!needs_begin_impl_frame_ || !client_ready_for_begin_impl_frame_ ||
164       (pending_swap_buffers_ >= max_frames_pending_ &&
165        max_frames_pending_ > 0)) {
166     skipped_begin_impl_frame_args_ = args;
167   } else {
168     client_ready_for_begin_impl_frame_ = false;
169     client_->BeginImplFrame(args);
170     // args might be an alias for skipped_begin_impl_frame_args_.
171     // Do not reset it before calling BeginImplFrame!
172     skipped_begin_impl_frame_args_ = BeginFrameArgs();
173   }
174 }
175 
RetroactiveBeginImplFrameDeadline()176 base::TimeTicks OutputSurface::RetroactiveBeginImplFrameDeadline() {
177   // TODO(brianderson): Remove the alternative deadline once we have better
178   // deadline estimations.
179   base::TimeTicks alternative_deadline =
180       skipped_begin_impl_frame_args_.frame_time +
181       BeginFrameArgs::DefaultRetroactiveBeginFramePeriod();
182   return std::max(skipped_begin_impl_frame_args_.deadline,
183                   alternative_deadline);
184 }
185 
PostCheckForRetroactiveBeginImplFrame()186 void OutputSurface::PostCheckForRetroactiveBeginImplFrame() {
187   if (!skipped_begin_impl_frame_args_.IsValid() ||
188       check_for_retroactive_begin_impl_frame_pending_)
189     return;
190 
191   base::MessageLoop::current()->PostTask(
192      FROM_HERE,
193      base::Bind(&OutputSurface::CheckForRetroactiveBeginImplFrame,
194                 weak_ptr_factory_.GetWeakPtr()));
195   check_for_retroactive_begin_impl_frame_pending_ = true;
196 }
197 
CheckForRetroactiveBeginImplFrame()198 void OutputSurface::CheckForRetroactiveBeginImplFrame() {
199   TRACE_EVENT0("cc", "OutputSurface::CheckForRetroactiveBeginImplFrame");
200   check_for_retroactive_begin_impl_frame_pending_ = false;
201   if (gfx::FrameTime::Now() < RetroactiveBeginImplFrameDeadline())
202     BeginImplFrame(skipped_begin_impl_frame_args_);
203 }
204 
DidSwapBuffers()205 void OutputSurface::DidSwapBuffers() {
206   pending_swap_buffers_++;
207   TRACE_EVENT1("cc", "OutputSurface::DidSwapBuffers",
208                "pending_swap_buffers_", pending_swap_buffers_);
209   client_->DidSwapBuffers();
210   if (frame_rate_controller_)
211     frame_rate_controller_->DidSwapBuffers();
212   PostCheckForRetroactiveBeginImplFrame();
213 }
214 
OnSwapBuffersComplete()215 void OutputSurface::OnSwapBuffersComplete() {
216   pending_swap_buffers_--;
217   TRACE_EVENT1("cc", "OutputSurface::OnSwapBuffersComplete",
218                "pending_swap_buffers_", pending_swap_buffers_);
219   client_->OnSwapBuffersComplete();
220   if (frame_rate_controller_)
221     frame_rate_controller_->DidSwapBuffersComplete();
222   PostCheckForRetroactiveBeginImplFrame();
223 }
224 
ReclaimResources(const CompositorFrameAck * ack)225 void OutputSurface::ReclaimResources(const CompositorFrameAck* ack) {
226   client_->ReclaimResources(ack);
227 }
228 
DidLoseOutputSurface()229 void OutputSurface::DidLoseOutputSurface() {
230   TRACE_EVENT0("cc", "OutputSurface::DidLoseOutputSurface");
231   client_ready_for_begin_impl_frame_ = true;
232   pending_swap_buffers_ = 0;
233   skipped_begin_impl_frame_args_ = BeginFrameArgs();
234   if (frame_rate_controller_)
235     frame_rate_controller_->SetActive(false);
236   pending_gpu_latency_query_ids_.clear();
237   available_gpu_latency_query_ids_.clear();
238   client_->DidLoseOutputSurface();
239 }
240 
SetExternalStencilTest(bool enabled)241 void OutputSurface::SetExternalStencilTest(bool enabled) {
242   external_stencil_test_enabled_ = enabled;
243 }
244 
SetExternalDrawConstraints(const gfx::Transform & transform,gfx::Rect viewport,gfx::Rect clip,bool valid_for_tile_management)245 void OutputSurface::SetExternalDrawConstraints(const gfx::Transform& transform,
246                                                gfx::Rect viewport,
247                                                gfx::Rect clip,
248                                                bool valid_for_tile_management) {
249   client_->SetExternalDrawConstraints(
250       transform, viewport, clip, valid_for_tile_management);
251 }
252 
~OutputSurface()253 OutputSurface::~OutputSurface() {
254   if (frame_rate_controller_)
255     frame_rate_controller_->SetActive(false);
256   ResetContext3d();
257 }
258 
HasExternalStencilTest() const259 bool OutputSurface::HasExternalStencilTest() const {
260   return external_stencil_test_enabled_;
261 }
262 
ForcedDrawToSoftwareDevice() const263 bool OutputSurface::ForcedDrawToSoftwareDevice() const { return false; }
264 
BindToClient(OutputSurfaceClient * client)265 bool OutputSurface::BindToClient(OutputSurfaceClient* client) {
266   DCHECK(client);
267   client_ = client;
268   bool success = true;
269 
270   if (context_provider_) {
271     success = context_provider_->BindToCurrentThread();
272     if (success)
273       SetUpContext3d();
274   }
275 
276   if (!success)
277     client_ = NULL;
278 
279   return success;
280 }
281 
InitializeAndSetContext3d(scoped_refptr<ContextProvider> context_provider,scoped_refptr<ContextProvider> offscreen_context_provider)282 bool OutputSurface::InitializeAndSetContext3d(
283     scoped_refptr<ContextProvider> context_provider,
284     scoped_refptr<ContextProvider> offscreen_context_provider) {
285   DCHECK(!context_provider_);
286   DCHECK(context_provider);
287   DCHECK(client_);
288 
289   bool success = false;
290   if (context_provider->BindToCurrentThread()) {
291     context_provider_ = context_provider;
292     SetUpContext3d();
293     if (client_->DeferredInitialize(offscreen_context_provider))
294       success = true;
295   }
296 
297   if (!success)
298     ResetContext3d();
299 
300   return success;
301 }
302 
ReleaseGL()303 void OutputSurface::ReleaseGL() {
304   DCHECK(client_);
305   DCHECK(context_provider_);
306   client_->ReleaseGL();
307   ResetContext3d();
308 }
309 
SetUpContext3d()310 void OutputSurface::SetUpContext3d() {
311   DCHECK(context_provider_);
312   DCHECK(client_);
313 
314   context_provider_->SetLostContextCallback(
315       base::Bind(&OutputSurface::DidLoseOutputSurface,
316                  base::Unretained(this)));
317   context_provider_->ContextSupport()->SetSwapBuffersCompleteCallback(
318       base::Bind(&OutputSurface::OnSwapBuffersComplete,
319                  base::Unretained(this)));
320   context_provider_->SetMemoryPolicyChangedCallback(
321       base::Bind(&OutputSurface::SetMemoryPolicy,
322                  base::Unretained(this)));
323 }
324 
ResetContext3d()325 void OutputSurface::ResetContext3d() {
326   if (context_provider_.get()) {
327     while (!pending_gpu_latency_query_ids_.empty()) {
328       unsigned query_id = pending_gpu_latency_query_ids_.front();
329       pending_gpu_latency_query_ids_.pop_front();
330       context_provider_->Context3d()->deleteQueryEXT(query_id);
331     }
332     while (!available_gpu_latency_query_ids_.empty()) {
333       unsigned query_id = available_gpu_latency_query_ids_.front();
334       available_gpu_latency_query_ids_.pop_front();
335       context_provider_->Context3d()->deleteQueryEXT(query_id);
336     }
337     context_provider_->SetLostContextCallback(
338         ContextProvider::LostContextCallback());
339     context_provider_->SetMemoryPolicyChangedCallback(
340         ContextProvider::MemoryPolicyChangedCallback());
341     if (gpu::ContextSupport* support = context_provider_->ContextSupport())
342       support->SetSwapBuffersCompleteCallback(base::Closure());
343   }
344   context_provider_ = NULL;
345 }
346 
EnsureBackbuffer()347 void OutputSurface::EnsureBackbuffer() {
348   if (software_device_)
349     software_device_->EnsureBackbuffer();
350 }
351 
DiscardBackbuffer()352 void OutputSurface::DiscardBackbuffer() {
353   if (context_provider_)
354     context_provider_->ContextGL()->DiscardBackbufferCHROMIUM();
355   if (software_device_)
356     software_device_->DiscardBackbuffer();
357 }
358 
Reshape(gfx::Size size,float scale_factor)359 void OutputSurface::Reshape(gfx::Size size, float scale_factor) {
360   if (size == surface_size_ && scale_factor == device_scale_factor_)
361     return;
362 
363   surface_size_ = size;
364   device_scale_factor_ = scale_factor;
365   if (context_provider_) {
366     context_provider_->Context3d()->reshapeWithScaleFactor(
367         size.width(), size.height(), scale_factor);
368   }
369   if (software_device_)
370     software_device_->Resize(size);
371 }
372 
SurfaceSize() const373 gfx::Size OutputSurface::SurfaceSize() const {
374   return surface_size_;
375 }
376 
BindFramebuffer()377 void OutputSurface::BindFramebuffer() {
378   DCHECK(context_provider_);
379   context_provider_->Context3d()->bindFramebuffer(GL_FRAMEBUFFER, 0);
380 }
381 
SwapBuffers(CompositorFrame * frame)382 void OutputSurface::SwapBuffers(CompositorFrame* frame) {
383   if (frame->software_frame_data) {
384     PostSwapBuffersComplete();
385     DidSwapBuffers();
386     return;
387   }
388 
389   DCHECK(context_provider_);
390   DCHECK(frame->gl_frame_data);
391 
392   UpdateAndMeasureGpuLatency();
393   if (frame->gl_frame_data->sub_buffer_rect ==
394       gfx::Rect(frame->gl_frame_data->size)) {
395     context_provider_->ContextSupport()->Swap();
396   } else {
397     context_provider_->ContextSupport()->PartialSwapBuffers(
398         frame->gl_frame_data->sub_buffer_rect);
399   }
400 
401   DidSwapBuffers();
402 }
403 
GpuLatencyEstimate()404 base::TimeDelta OutputSurface::GpuLatencyEstimate() {
405   if (context_provider_ && !capabilities_.adjust_deadline_for_parent)
406     return gpu_latency_history_.Percentile(kGpuLatencyEstimationPercentile);
407   else
408     return base::TimeDelta();
409 }
410 
UpdateAndMeasureGpuLatency()411 void OutputSurface::UpdateAndMeasureGpuLatency() {
412   return;  // http://crbug.com/306690  tracks re-enabling latency queries.
413 
414   // We only care about GPU latency for surfaces that do not have a parent
415   // compositor, since surfaces that do have a parent compositor can use
416   // mailboxes or delegated rendering to send frames to their parent without
417   // incurring GPU latency.
418   if (capabilities_.adjust_deadline_for_parent)
419     return;
420 
421   while (pending_gpu_latency_query_ids_.size()) {
422     unsigned query_id = pending_gpu_latency_query_ids_.front();
423     unsigned query_complete = 1;
424     context_provider_->Context3d()->getQueryObjectuivEXT(
425         query_id, GL_QUERY_RESULT_AVAILABLE_EXT, &query_complete);
426     if (!query_complete)
427       break;
428 
429     unsigned value = 0;
430     context_provider_->Context3d()->getQueryObjectuivEXT(
431         query_id, GL_QUERY_RESULT_EXT, &value);
432     pending_gpu_latency_query_ids_.pop_front();
433     available_gpu_latency_query_ids_.push_back(query_id);
434 
435     base::TimeDelta latency = base::TimeDelta::FromMicroseconds(value);
436     base::TimeDelta latency_estimate = GpuLatencyEstimate();
437     gpu_latency_history_.InsertSample(latency);
438 
439     base::TimeDelta latency_overestimate;
440     base::TimeDelta latency_underestimate;
441     if (latency > latency_estimate)
442       latency_underestimate = latency - latency_estimate;
443     else
444       latency_overestimate = latency_estimate - latency;
445     UMA_HISTOGRAM_CUSTOM_TIMES("Renderer.GpuLatency",
446                                latency,
447                                base::TimeDelta::FromMilliseconds(1),
448                                base::TimeDelta::FromMilliseconds(100),
449                                50);
450     UMA_HISTOGRAM_CUSTOM_TIMES("Renderer.GpuLatencyUnderestimate",
451                                latency_underestimate,
452                                base::TimeDelta::FromMilliseconds(1),
453                                base::TimeDelta::FromMilliseconds(100),
454                                50);
455     UMA_HISTOGRAM_CUSTOM_TIMES("Renderer.GpuLatencyOverestimate",
456                                latency_overestimate,
457                                base::TimeDelta::FromMilliseconds(1),
458                                base::TimeDelta::FromMilliseconds(100),
459                                50);
460   }
461 
462   unsigned gpu_latency_query_id;
463   if (available_gpu_latency_query_ids_.size()) {
464     gpu_latency_query_id = available_gpu_latency_query_ids_.front();
465     available_gpu_latency_query_ids_.pop_front();
466   } else {
467     gpu_latency_query_id = context_provider_->Context3d()->createQueryEXT();
468   }
469 
470   context_provider_->Context3d()->beginQueryEXT(GL_LATENCY_QUERY_CHROMIUM,
471                                                 gpu_latency_query_id);
472   context_provider_->Context3d()->endQueryEXT(GL_LATENCY_QUERY_CHROMIUM);
473   pending_gpu_latency_query_ids_.push_back(gpu_latency_query_id);
474 }
475 
PostSwapBuffersComplete()476 void OutputSurface::PostSwapBuffersComplete() {
477   base::MessageLoop::current()->PostTask(
478       FROM_HERE,
479       base::Bind(&OutputSurface::OnSwapBuffersComplete,
480                  weak_ptr_factory_.GetWeakPtr()));
481 }
482 
SetMemoryPolicy(const ManagedMemoryPolicy & policy)483 void OutputSurface::SetMemoryPolicy(const ManagedMemoryPolicy& policy) {
484   TRACE_EVENT1("cc", "OutputSurface::SetMemoryPolicy",
485                "bytes_limit_when_visible", policy.bytes_limit_when_visible);
486   // Just ignore the memory manager when it says to set the limit to zero
487   // bytes. This will happen when the memory manager thinks that the renderer
488   // is not visible (which the renderer knows better).
489   if (policy.bytes_limit_when_visible)
490     client_->SetMemoryPolicy(policy);
491 }
492 
493 }  // namespace cc
494