Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / cc / output / output_surface.cc
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/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"
32
33 using std::set;
34 using std::string;
35 using std::vector;
36
37 namespace {
38
39 const size_t kGpuLatencyHistorySize = 60;
40 const double kGpuLatencyEstimationPercentile = 100.0;
41
42 }
43
44 namespace cc {
45
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),
53       client_(NULL),
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) {}
58
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),
66       client_(NULL),
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) {}
71
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),
81       client_(NULL),
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) {}
86
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);
95     else
96       time_source = DelayBasedTimeSource::Create(interval, task_runner);
97     frame_rate_controller_.reset(new FrameRateController(time_source));
98   } else {
99     frame_rate_controller_.reset(new FrameRateController(task_runner));
100   }
101
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());
107
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();
112 }
113
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;
118 }
119
120 void OutputSurface::CommitVSyncParameters(base::TimeTicks timebase,
121                                           base::TimeDelta interval) {
122   TRACE_EVENT2("cc",
123                "OutputSurface::CommitVSyncParameters",
124                "timebase",
125                (timebase - base::TimeTicks()).InSecondsF(),
126                "interval",
127                interval.InSecondsF());
128   if (frame_rate_controller_)
129     frame_rate_controller_->SetTimebaseAndInterval(timebase, interval);
130 }
131
132 void OutputSurface::FrameRateControllerTick(bool throttled,
133                                             const BeginFrameArgs& args) {
134   DCHECK(frame_rate_controller_);
135   if (throttled)
136     skipped_begin_impl_frame_args_ = args;
137   else
138     BeginImplFrame(args);
139 }
140
141 // Forwarded to OutputSurfaceClient
142 void OutputSurface::SetNeedsRedrawRect(const gfx::Rect& damage_rect) {
143   TRACE_EVENT0("cc", "OutputSurface::SetNeedsRedrawRect");
144   client_->SetNeedsRedrawRect(damage_rect);
145 }
146
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;
155   }
156   if (needs_begin_impl_frame_)
157     PostCheckForRetroactiveBeginImplFrame();
158 }
159
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;
169   } else {
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();
175   }
176 }
177
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);
186 }
187
188 void OutputSurface::PostCheckForRetroactiveBeginImplFrame() {
189   if (!skipped_begin_impl_frame_args_.IsValid() ||
190       check_for_retroactive_begin_impl_frame_pending_)
191     return;
192
193   base::MessageLoop::current()->PostTask(
194      FROM_HERE,
195      base::Bind(&OutputSurface::CheckForRetroactiveBeginImplFrame,
196                 weak_ptr_factory_.GetWeakPtr()));
197   check_for_retroactive_begin_impl_frame_pending_ = true;
198 }
199
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_);
205 }
206
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();
215 }
216
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();
225 }
226
227 void OutputSurface::ReclaimResources(const CompositorFrameAck* ack) {
228   client_->ReclaimResources(ack);
229 }
230
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();
241 }
242
243 void OutputSurface::SetExternalStencilTest(bool enabled) {
244   external_stencil_test_enabled_ = enabled;
245 }
246
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);
253 }
254
255 OutputSurface::~OutputSurface() {
256   if (frame_rate_controller_)
257     frame_rate_controller_->SetActive(false);
258   ResetContext3d();
259 }
260
261 bool OutputSurface::HasExternalStencilTest() const {
262   return external_stencil_test_enabled_;
263 }
264
265 bool OutputSurface::ForcedDrawToSoftwareDevice() const { return false; }
266
267 bool OutputSurface::BindToClient(OutputSurfaceClient* client) {
268   DCHECK(client);
269   client_ = client;
270   bool success = true;
271
272   if (context_provider_) {
273     success = context_provider_->BindToCurrentThread();
274     if (success)
275       SetUpContext3d();
276   }
277
278   if (!success)
279     client_ = NULL;
280
281   return success;
282 }
283
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);
289   DCHECK(client_);
290
291   bool success = false;
292   if (context_provider->BindToCurrentThread()) {
293     context_provider_ = context_provider;
294     SetUpContext3d();
295     if (client_->DeferredInitialize(offscreen_context_provider))
296       success = true;
297   }
298
299   if (!success)
300     ResetContext3d();
301
302   return success;
303 }
304
305 void OutputSurface::ReleaseGL() {
306   DCHECK(client_);
307   DCHECK(context_provider_);
308   client_->ReleaseGL();
309   ResetContext3d();
310 }
311
312 void OutputSurface::SetUpContext3d() {
313   DCHECK(context_provider_);
314   DCHECK(client_);
315
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)));
325 }
326
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);
333     }
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);
338     }
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());
345   }
346   context_provider_ = NULL;
347 }
348
349 void OutputSurface::EnsureBackbuffer() {
350   if (software_device_)
351     software_device_->EnsureBackbuffer();
352 }
353
354 void OutputSurface::DiscardBackbuffer() {
355   if (context_provider_)
356     context_provider_->ContextGL()->DiscardBackbufferCHROMIUM();
357   if (software_device_)
358     software_device_->DiscardBackbuffer();
359 }
360
361 void OutputSurface::Reshape(const gfx::Size& size, float scale_factor) {
362   if (size == surface_size_ && scale_factor == device_scale_factor_)
363     return;
364
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);
370   }
371   if (software_device_)
372     software_device_->Resize(size);
373 }
374
375 gfx::Size OutputSurface::SurfaceSize() const {
376   return surface_size_;
377 }
378
379 void OutputSurface::BindFramebuffer() {
380   DCHECK(context_provider_);
381   context_provider_->ContextGL()->BindFramebuffer(GL_FRAMEBUFFER, 0);
382 }
383
384 void OutputSurface::SwapBuffers(CompositorFrame* frame) {
385   if (frame->software_frame_data) {
386     PostSwapBuffersComplete();
387     DidSwapBuffers();
388     return;
389   }
390
391   DCHECK(context_provider_);
392   DCHECK(frame->gl_frame_data);
393
394   UpdateAndMeasureGpuLatency();
395   if (frame->gl_frame_data->sub_buffer_rect ==
396       gfx::Rect(frame->gl_frame_data->size)) {
397     context_provider_->ContextSupport()->Swap();
398   } else {
399     context_provider_->ContextSupport()->PartialSwapBuffers(
400         frame->gl_frame_data->sub_buffer_rect);
401   }
402
403   DidSwapBuffers();
404 }
405
406 base::TimeDelta OutputSurface::GpuLatencyEstimate() {
407   if (context_provider_ && !capabilities_.adjust_deadline_for_parent)
408     return gpu_latency_history_.Percentile(kGpuLatencyEstimationPercentile);
409   else
410     return base::TimeDelta();
411 }
412
413 void OutputSurface::UpdateAndMeasureGpuLatency() {
414   return;  // http://crbug.com/306690  tracks re-enabling latency queries.
415
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)
421     return;
422
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);
428     if (!query_complete)
429       break;
430
431     unsigned value = 0;
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);
436
437     base::TimeDelta latency = base::TimeDelta::FromMicroseconds(value);
438     base::TimeDelta latency_estimate = GpuLatencyEstimate();
439     gpu_latency_history_.InsertSample(latency);
440
441     base::TimeDelta latency_overestimate;
442     base::TimeDelta latency_underestimate;
443     if (latency > latency_estimate)
444       latency_underestimate = latency - latency_estimate;
445     else
446       latency_overestimate = latency_estimate - latency;
447     UMA_HISTOGRAM_CUSTOM_TIMES("Renderer.GpuLatency",
448                                latency,
449                                base::TimeDelta::FromMilliseconds(1),
450                                base::TimeDelta::FromMilliseconds(100),
451                                50);
452     UMA_HISTOGRAM_CUSTOM_TIMES("Renderer.GpuLatencyUnderestimate",
453                                latency_underestimate,
454                                base::TimeDelta::FromMilliseconds(1),
455                                base::TimeDelta::FromMilliseconds(100),
456                                50);
457     UMA_HISTOGRAM_CUSTOM_TIMES("Renderer.GpuLatencyOverestimate",
458                                latency_overestimate,
459                                base::TimeDelta::FromMilliseconds(1),
460                                base::TimeDelta::FromMilliseconds(100),
461                                50);
462   }
463
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();
468   } else {
469     context_provider_->ContextGL()->GenQueriesEXT(1, &gpu_latency_query_id);
470   }
471
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);
476 }
477
478 void OutputSurface::PostSwapBuffersComplete() {
479   base::MessageLoop::current()->PostTask(
480       FROM_HERE,
481       base::Bind(&OutputSurface::OnSwapBuffersComplete,
482                  weak_ptr_factory_.GetWeakPtr()));
483 }
484
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);
493 }
494
495 }  // namespace cc