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 "ui/gfx/frame_time.h"
28#include "ui/gfx/geometry/rect.h"
29#include "ui/gfx/geometry/size.h"
30
31using std::set;
32using std::string;
33using std::vector;
34
35namespace {
36
37const size_t kGpuLatencyHistorySize = 60;
38const double kGpuLatencyEstimationPercentile = 90.0;
39}
40
41namespace cc {
42
43OutputSurface::OutputSurface(
44    const scoped_refptr<ContextProvider>& context_provider)
45    : client_(NULL),
46      context_provider_(context_provider),
47      device_scale_factor_(-1),
48      external_stencil_test_enabled_(false),
49      gpu_latency_history_(kGpuLatencyHistorySize),
50      weak_ptr_factory_(this) {
51}
52
53OutputSurface::OutputSurface(scoped_ptr<SoftwareOutputDevice> software_device)
54    : client_(NULL),
55      software_device_(software_device.Pass()),
56      device_scale_factor_(-1),
57      external_stencil_test_enabled_(false),
58      gpu_latency_history_(kGpuLatencyHistorySize),
59      weak_ptr_factory_(this) {
60}
61
62OutputSurface::OutputSurface(
63    const scoped_refptr<ContextProvider>& context_provider,
64    scoped_ptr<SoftwareOutputDevice> software_device)
65    : client_(NULL),
66      context_provider_(context_provider),
67      software_device_(software_device.Pass()),
68      device_scale_factor_(-1),
69      external_stencil_test_enabled_(false),
70      gpu_latency_history_(kGpuLatencyHistorySize),
71      weak_ptr_factory_(this) {
72}
73
74void OutputSurface::CommitVSyncParameters(base::TimeTicks timebase,
75                                          base::TimeDelta interval) {
76  TRACE_EVENT2("cc",
77               "OutputSurface::CommitVSyncParameters",
78               "timebase",
79               (timebase - base::TimeTicks()).InSecondsF(),
80               "interval",
81               interval.InSecondsF());
82  client_->CommitVSyncParameters(timebase, interval);
83}
84
85// Forwarded to OutputSurfaceClient
86void OutputSurface::SetNeedsRedrawRect(const gfx::Rect& damage_rect) {
87  TRACE_EVENT0("cc", "OutputSurface::SetNeedsRedrawRect");
88  client_->SetNeedsRedrawRect(damage_rect);
89}
90
91void OutputSurface::ReclaimResources(const CompositorFrameAck* ack) {
92  client_->ReclaimResources(ack);
93}
94
95void OutputSurface::DidLoseOutputSurface() {
96  TRACE_EVENT0("cc", "OutputSurface::DidLoseOutputSurface");
97  pending_gpu_latency_query_ids_.clear();
98  available_gpu_latency_query_ids_.clear();
99  client_->DidLoseOutputSurface();
100}
101
102void OutputSurface::SetExternalStencilTest(bool enabled) {
103  external_stencil_test_enabled_ = enabled;
104}
105
106void OutputSurface::SetExternalDrawConstraints(
107    const gfx::Transform& transform,
108    const gfx::Rect& viewport,
109    const gfx::Rect& clip,
110    const gfx::Rect& viewport_rect_for_tile_priority,
111    const gfx::Transform& transform_for_tile_priority,
112    bool resourceless_software_draw) {
113  client_->SetExternalDrawConstraints(transform,
114                                      viewport,
115                                      clip,
116                                      viewport_rect_for_tile_priority,
117                                      transform_for_tile_priority,
118                                      resourceless_software_draw);
119}
120
121OutputSurface::~OutputSurface() {
122  ResetContext3d();
123}
124
125bool OutputSurface::HasExternalStencilTest() const {
126  return external_stencil_test_enabled_;
127}
128
129bool OutputSurface::BindToClient(OutputSurfaceClient* client) {
130  DCHECK(client);
131  client_ = client;
132  bool success = true;
133
134  if (context_provider_.get()) {
135    success = context_provider_->BindToCurrentThread();
136    if (success)
137      SetUpContext3d();
138  }
139
140  if (!success)
141    client_ = NULL;
142
143  return success;
144}
145
146bool OutputSurface::InitializeAndSetContext3d(
147    scoped_refptr<ContextProvider> context_provider) {
148  DCHECK(!context_provider_.get());
149  DCHECK(context_provider.get());
150  DCHECK(client_);
151
152  bool success = false;
153  if (context_provider->BindToCurrentThread()) {
154    context_provider_ = context_provider;
155    SetUpContext3d();
156    client_->DeferredInitialize();
157    success = true;
158  }
159
160  if (!success)
161    ResetContext3d();
162
163  return success;
164}
165
166void OutputSurface::ReleaseGL() {
167  DCHECK(client_);
168  DCHECK(context_provider_.get());
169  client_->ReleaseGL();
170  DCHECK(!context_provider_.get());
171}
172
173void OutputSurface::SetUpContext3d() {
174  DCHECK(context_provider_.get());
175  DCHECK(client_);
176
177  context_provider_->SetLostContextCallback(
178      base::Bind(&OutputSurface::DidLoseOutputSurface,
179                 base::Unretained(this)));
180  context_provider_->ContextSupport()->SetSwapBuffersCompleteCallback(
181      base::Bind(&OutputSurface::OnSwapBuffersComplete,
182                 base::Unretained(this)));
183  context_provider_->SetMemoryPolicyChangedCallback(
184      base::Bind(&OutputSurface::SetMemoryPolicy,
185                 base::Unretained(this)));
186}
187
188void OutputSurface::ReleaseContextProvider() {
189  DCHECK(client_);
190  DCHECK(context_provider_.get());
191  ResetContext3d();
192}
193
194void OutputSurface::ResetContext3d() {
195  if (context_provider_.get()) {
196    while (!pending_gpu_latency_query_ids_.empty()) {
197      unsigned query_id = pending_gpu_latency_query_ids_.front();
198      pending_gpu_latency_query_ids_.pop_front();
199      context_provider_->ContextGL()->DeleteQueriesEXT(1, &query_id);
200    }
201    while (!available_gpu_latency_query_ids_.empty()) {
202      unsigned query_id = available_gpu_latency_query_ids_.front();
203      available_gpu_latency_query_ids_.pop_front();
204      context_provider_->ContextGL()->DeleteQueriesEXT(1, &query_id);
205    }
206    context_provider_->SetLostContextCallback(
207        ContextProvider::LostContextCallback());
208    context_provider_->SetMemoryPolicyChangedCallback(
209        ContextProvider::MemoryPolicyChangedCallback());
210    if (gpu::ContextSupport* support = context_provider_->ContextSupport())
211      support->SetSwapBuffersCompleteCallback(base::Closure());
212  }
213  context_provider_ = NULL;
214}
215
216void OutputSurface::EnsureBackbuffer() {
217  if (software_device_)
218    software_device_->EnsureBackbuffer();
219}
220
221void OutputSurface::DiscardBackbuffer() {
222  if (context_provider_.get())
223    context_provider_->ContextGL()->DiscardBackbufferCHROMIUM();
224  if (software_device_)
225    software_device_->DiscardBackbuffer();
226}
227
228void OutputSurface::Reshape(const gfx::Size& size, float scale_factor) {
229  if (size == surface_size_ && scale_factor == device_scale_factor_)
230    return;
231
232  surface_size_ = size;
233  device_scale_factor_ = scale_factor;
234  if (context_provider_.get()) {
235    context_provider_->ContextGL()->ResizeCHROMIUM(
236        size.width(), size.height(), scale_factor);
237  }
238  if (software_device_)
239    software_device_->Resize(size, scale_factor);
240}
241
242gfx::Size OutputSurface::SurfaceSize() const {
243  return surface_size_;
244}
245
246void OutputSurface::BindFramebuffer() {
247  DCHECK(context_provider_.get());
248  context_provider_->ContextGL()->BindFramebuffer(GL_FRAMEBUFFER, 0);
249}
250
251void OutputSurface::SwapBuffers(CompositorFrame* frame) {
252  if (frame->software_frame_data) {
253    PostSwapBuffersComplete();
254    client_->DidSwapBuffers();
255    return;
256  }
257
258  DCHECK(context_provider_.get());
259  DCHECK(frame->gl_frame_data);
260
261  UpdateAndMeasureGpuLatency();
262  if (frame->gl_frame_data->sub_buffer_rect ==
263      gfx::Rect(frame->gl_frame_data->size)) {
264    context_provider_->ContextSupport()->Swap();
265  } else {
266    context_provider_->ContextSupport()->PartialSwapBuffers(
267        frame->gl_frame_data->sub_buffer_rect);
268  }
269
270  client_->DidSwapBuffers();
271}
272
273base::TimeDelta OutputSurface::GpuLatencyEstimate() {
274  if (context_provider_.get() && !capabilities_.adjust_deadline_for_parent)
275    return gpu_latency_history_.Percentile(kGpuLatencyEstimationPercentile);
276  else
277    return base::TimeDelta();
278}
279
280void OutputSurface::UpdateAndMeasureGpuLatency() {
281  // We only care about GPU latency for surfaces that do not have a parent
282  // compositor, since surfaces that do have a parent compositor can use
283  // mailboxes or delegated rendering to send frames to their parent without
284  // incurring GPU latency.
285  if (capabilities_.adjust_deadline_for_parent)
286    return;
287
288  // Try to collect pending queries which may have completed
289  while (pending_gpu_latency_query_ids_.size()) {
290    unsigned query_id = pending_gpu_latency_query_ids_.front();
291    unsigned query_complete = 1;
292    context_provider_->ContextGL()->GetQueryObjectuivEXT(
293        query_id, GL_QUERY_RESULT_AVAILABLE_EXT, &query_complete);
294    if (!query_complete)
295      break;
296
297    unsigned value = 0;
298    context_provider_->ContextGL()->GetQueryObjectuivEXT(
299        query_id, GL_QUERY_RESULT_EXT, &value);
300    pending_gpu_latency_query_ids_.pop_front();
301    available_gpu_latency_query_ids_.push_back(query_id);
302
303    base::TimeDelta latency = base::TimeDelta::FromMicroseconds(value);
304    base::TimeDelta latency_estimate = GpuLatencyEstimate();
305    gpu_latency_history_.InsertSample(latency);
306
307    base::TimeDelta latency_overestimate;
308    base::TimeDelta latency_underestimate;
309    if (latency > latency_estimate)
310      latency_underestimate = latency - latency_estimate;
311    else
312      latency_overestimate = latency_estimate - latency;
313    UMA_HISTOGRAM_CUSTOM_TIMES("Renderer.GpuLatency",
314                               latency,
315                               base::TimeDelta::FromMilliseconds(1),
316                               base::TimeDelta::FromMilliseconds(100),
317                               50);
318    UMA_HISTOGRAM_CUSTOM_TIMES("Renderer.GpuLatencyUnderestimate",
319                               latency_underestimate,
320                               base::TimeDelta::FromMilliseconds(1),
321                               base::TimeDelta::FromMilliseconds(100),
322                               50);
323    UMA_HISTOGRAM_CUSTOM_TIMES("Renderer.GpuLatencyOverestimate",
324                               latency_overestimate,
325                               base::TimeDelta::FromMilliseconds(1),
326                               base::TimeDelta::FromMilliseconds(100),
327                               50);
328  }
329
330  // Generate new query id or use a previous id which has completed
331  unsigned gpu_latency_query_id;
332  if (available_gpu_latency_query_ids_.size()) {
333    gpu_latency_query_id = available_gpu_latency_query_ids_.front();
334    available_gpu_latency_query_ids_.pop_front();
335  } else {
336    context_provider_->ContextGL()->GenQueriesEXT(1, &gpu_latency_query_id);
337  }
338
339  // Send new latency query
340  context_provider_->ContextGL()->BeginQueryEXT(GL_LATENCY_QUERY_CHROMIUM,
341                                                gpu_latency_query_id);
342  context_provider_->ContextGL()->EndQueryEXT(GL_LATENCY_QUERY_CHROMIUM);
343  pending_gpu_latency_query_ids_.push_back(gpu_latency_query_id);
344}
345
346void OutputSurface::PostSwapBuffersComplete() {
347  base::MessageLoop::current()->PostTask(
348      FROM_HERE,
349      base::Bind(&OutputSurface::OnSwapBuffersComplete,
350                 weak_ptr_factory_.GetWeakPtr()));
351}
352
353// We don't post tasks bound to the client directly since they might run
354// after the OutputSurface has been destroyed.
355void OutputSurface::OnSwapBuffersComplete() {
356  client_->DidSwapBuffersComplete();
357}
358
359void OutputSurface::SetMemoryPolicy(const ManagedMemoryPolicy& policy) {
360  TRACE_EVENT1("cc", "OutputSurface::SetMemoryPolicy",
361               "bytes_limit_when_visible", policy.bytes_limit_when_visible);
362  // Just ignore the memory manager when it says to set the limit to zero
363  // bytes. This will happen when the memory manager thinks that the renderer
364  // is not visible (which the renderer knows better).
365  if (policy.bytes_limit_when_visible)
366    client_->SetMemoryPolicy(policy);
367}
368
369}  // namespace cc
370