Upstream version 10.39.225.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 "ui/gfx/frame_time.h"
28 #include "ui/gfx/geometry/rect.h"
29 #include "ui/gfx/geometry/size.h"
30
31 using std::set;
32 using std::string;
33 using std::vector;
34
35 namespace {
36
37 const size_t kGpuLatencyHistorySize = 60;
38 const double kGpuLatencyEstimationPercentile = 90.0;
39 }
40
41 namespace cc {
42
43 OutputSurface::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
53 OutputSurface::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
62 OutputSurface::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
74 void 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
86 void OutputSurface::SetNeedsRedrawRect(const gfx::Rect& damage_rect) {
87   TRACE_EVENT0("cc", "OutputSurface::SetNeedsRedrawRect");
88   client_->SetNeedsRedrawRect(damage_rect);
89 }
90
91 void OutputSurface::ReclaimResources(const CompositorFrameAck* ack) {
92   client_->ReclaimResources(ack);
93 }
94
95 void 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
102 void OutputSurface::SetExternalStencilTest(bool enabled) {
103   external_stencil_test_enabled_ = enabled;
104 }
105
106 void 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
121 OutputSurface::~OutputSurface() {
122   ResetContext3d();
123 }
124
125 bool OutputSurface::HasExternalStencilTest() const {
126   return external_stencil_test_enabled_;
127 }
128
129 bool 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
146 bool 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
166 void OutputSurface::ReleaseGL() {
167   DCHECK(client_);
168   DCHECK(context_provider_.get());
169   client_->ReleaseGL();
170   DCHECK(!context_provider_.get());
171 }
172
173 void 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
188 void OutputSurface::ReleaseContextProvider() {
189   DCHECK(client_);
190   DCHECK(context_provider_.get());
191   ResetContext3d();
192 }
193
194 void 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
216 void OutputSurface::EnsureBackbuffer() {
217   if (software_device_)
218     software_device_->EnsureBackbuffer();
219 }
220
221 void OutputSurface::DiscardBackbuffer() {
222   if (context_provider_.get())
223     context_provider_->ContextGL()->DiscardBackbufferCHROMIUM();
224   if (software_device_)
225     software_device_->DiscardBackbuffer();
226 }
227
228 void 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
242 gfx::Size OutputSurface::SurfaceSize() const {
243   return surface_size_;
244 }
245
246 void OutputSurface::BindFramebuffer() {
247   DCHECK(context_provider_.get());
248   context_provider_->ContextGL()->BindFramebuffer(GL_FRAMEBUFFER, 0);
249 }
250
251 void 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
273 base::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
280 void 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
346 void 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.
355 void OutputSurface::OnSwapBuffersComplete() {
356   client_->DidSwapBuffersComplete();
357 }
358
359 void 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