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