Declaring the weak_ptr_factory in proper order in src/cc.
[chromium-blink-merge.git] / cc / output / output_surface.cc
blob2b6b7829999ef01c60648b6de7ed9acb4dce1fe7
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.
5 #include "cc/output/output_surface.h"
7 #include <algorithm>
8 #include <set>
9 #include <string>
10 #include <vector>
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"
31 using std::set;
32 using std::string;
33 using std::vector;
35 namespace {
37 const size_t kGpuLatencyHistorySize = 60;
38 const double kGpuLatencyEstimationPercentile = 90.0;
41 namespace cc {
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) {
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) {
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) {
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);
85 // Forwarded to OutputSurfaceClient
86 void OutputSurface::SetNeedsRedrawRect(const gfx::Rect& damage_rect) {
87 TRACE_EVENT0("cc", "OutputSurface::SetNeedsRedrawRect");
88 client_->SetNeedsRedrawRect(damage_rect);
91 void OutputSurface::ReclaimResources(const CompositorFrameAck* ack) {
92 client_->ReclaimResources(ack);
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();
102 void OutputSurface::SetExternalStencilTest(bool enabled) {
103 external_stencil_test_enabled_ = enabled;
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);
121 OutputSurface::~OutputSurface() {
122 ResetContext3d();
125 bool OutputSurface::HasExternalStencilTest() const {
126 return external_stencil_test_enabled_;
129 bool OutputSurface::BindToClient(OutputSurfaceClient* client) {
130 DCHECK(client);
131 client_ = client;
132 bool success = true;
134 if (context_provider_.get()) {
135 success = context_provider_->BindToCurrentThread();
136 if (success)
137 SetUpContext3d();
140 if (!success)
141 client_ = NULL;
143 return success;
146 bool OutputSurface::InitializeAndSetContext3d(
147 scoped_refptr<ContextProvider> context_provider) {
148 DCHECK(!context_provider_.get());
149 DCHECK(context_provider.get());
150 DCHECK(client_);
152 bool success = false;
153 if (context_provider->BindToCurrentThread()) {
154 context_provider_ = context_provider;
155 SetUpContext3d();
156 client_->DeferredInitialize();
157 success = true;
160 if (!success)
161 ResetContext3d();
163 return success;
166 void OutputSurface::ReleaseGL() {
167 DCHECK(client_);
168 DCHECK(context_provider_.get());
169 client_->ReleaseGL();
170 DCHECK(!context_provider_.get());
173 void OutputSurface::SetUpContext3d() {
174 DCHECK(context_provider_.get());
175 DCHECK(client_);
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)));
188 void OutputSurface::ReleaseContextProvider() {
189 DCHECK(client_);
190 DCHECK(context_provider_.get());
191 ResetContext3d();
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);
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);
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());
213 context_provider_ = NULL;
216 void OutputSurface::EnsureBackbuffer() {
217 if (software_device_)
218 software_device_->EnsureBackbuffer();
221 void OutputSurface::DiscardBackbuffer() {
222 if (context_provider_.get())
223 context_provider_->ContextGL()->DiscardBackbufferCHROMIUM();
224 if (software_device_)
225 software_device_->DiscardBackbuffer();
228 void OutputSurface::Reshape(const gfx::Size& size, float scale_factor) {
229 if (size == surface_size_ && scale_factor == device_scale_factor_)
230 return;
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);
238 if (software_device_)
239 software_device_->Resize(size, scale_factor);
242 gfx::Size OutputSurface::SurfaceSize() const {
243 return surface_size_;
246 void OutputSurface::BindFramebuffer() {
247 DCHECK(context_provider_.get());
248 context_provider_->ContextGL()->BindFramebuffer(GL_FRAMEBUFFER, 0);
251 void OutputSurface::SwapBuffers(CompositorFrame* frame) {
252 if (frame->software_frame_data) {
253 PostSwapBuffersComplete();
254 client_->DidSwapBuffers();
255 return;
258 DCHECK(context_provider_.get());
259 DCHECK(frame->gl_frame_data);
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);
270 client_->DidSwapBuffers();
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();
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;
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;
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);
303 base::TimeDelta latency = base::TimeDelta::FromMicroseconds(value);
304 base::TimeDelta latency_estimate = GpuLatencyEstimate();
305 gpu_latency_history_.InsertSample(latency);
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);
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);
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);
346 void OutputSurface::PostSwapBuffersComplete() {
347 base::MessageLoop::current()->PostTask(
348 FROM_HERE,
349 base::Bind(&OutputSurface::OnSwapBuffersComplete,
350 weak_ptr_factory_.GetWeakPtr()));
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();
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);
369 } // namespace cc