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