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
34using std::set;
35using std::string;
36using std::vector;
37
38namespace {
39
40const size_t kGpuLatencyHistorySize = 60;
41const double kGpuLatencyEstimationPercentile = 100.0;
42
43}
44
45namespace cc {
46
47OutputSurface::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
60OutputSurface::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
73OutputSurface::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
88void 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
115void 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
121void 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
130void 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
140void OutputSurface::SetNeedsRedrawRect(gfx::Rect damage_rect) {
141  TRACE_EVENT0("cc", "OutputSurface::SetNeedsRedrawRect");
142  client_->SetNeedsRedrawRect(damage_rect);
143}
144
145void 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
158void 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
176base::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
186void 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
198void 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
205void 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
215void 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
225void OutputSurface::ReclaimResources(const CompositorFrameAck* ack) {
226  client_->ReclaimResources(ack);
227}
228
229void 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
241void OutputSurface::SetExternalStencilTest(bool enabled) {
242  external_stencil_test_enabled_ = enabled;
243}
244
245void 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
253OutputSurface::~OutputSurface() {
254  if (frame_rate_controller_)
255    frame_rate_controller_->SetActive(false);
256  ResetContext3d();
257}
258
259bool OutputSurface::HasExternalStencilTest() const {
260  return external_stencil_test_enabled_;
261}
262
263bool OutputSurface::ForcedDrawToSoftwareDevice() const { return false; }
264
265bool 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
282bool 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
303void OutputSurface::ReleaseGL() {
304  DCHECK(client_);
305  DCHECK(context_provider_);
306  client_->ReleaseGL();
307  ResetContext3d();
308}
309
310void 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
325void 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
347void OutputSurface::EnsureBackbuffer() {
348  if (software_device_)
349    software_device_->EnsureBackbuffer();
350}
351
352void OutputSurface::DiscardBackbuffer() {
353  if (context_provider_)
354    context_provider_->ContextGL()->DiscardBackbufferCHROMIUM();
355  if (software_device_)
356    software_device_->DiscardBackbuffer();
357}
358
359void 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
373gfx::Size OutputSurface::SurfaceSize() const {
374  return surface_size_;
375}
376
377void OutputSurface::BindFramebuffer() {
378  DCHECK(context_provider_);
379  context_provider_->Context3d()->bindFramebuffer(GL_FRAMEBUFFER, 0);
380}
381
382void 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
404base::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
411void 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
476void OutputSurface::PostSwapBuffersComplete() {
477  base::MessageLoop::current()->PostTask(
478      FROM_HERE,
479      base::Bind(&OutputSurface::OnSwapBuffersComplete,
480                 weak_ptr_factory_.GetWeakPtr()));
481}
482
483void 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