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"
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"
39 const size_t kGpuLatencyHistorySize = 60;
40 const double kGpuLatencyEstimationPercentile = 100.0;
46 OutputSurface::OutputSurface(scoped_refptr<ContextProvider> context_provider)
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) {
55 OutputSurface::OutputSurface(scoped_ptr<SoftwareOutputDevice> software_device)
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) {
64 OutputSurface::OutputSurface(scoped_refptr<ContextProvider> context_provider,
65 scoped_ptr<SoftwareOutputDevice> software_device)
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) {
75 void OutputSurface::CommitVSyncParameters(base::TimeTicks timebase,
76 base::TimeDelta interval) {
78 "OutputSurface::CommitVSyncParameters",
80 (timebase - base::TimeTicks()).InSecondsF(),
82 interval.InSecondsF());
83 client_->CommitVSyncParameters(timebase, interval);
86 // Forwarded to OutputSurfaceClient
87 void OutputSurface::SetNeedsRedrawRect(const gfx::Rect& damage_rect) {
88 TRACE_EVENT0("cc", "OutputSurface::SetNeedsRedrawRect");
89 client_->SetNeedsRedrawRect(damage_rect);
92 void OutputSurface::ReclaimResources(const CompositorFrameAck* ack) {
93 client_->ReclaimResources(ack);
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();
103 void OutputSurface::SetExternalStencilTest(bool enabled) {
104 external_stencil_test_enabled_ = enabled;
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);
115 OutputSurface::~OutputSurface() {
119 bool OutputSurface::HasExternalStencilTest() const {
120 return external_stencil_test_enabled_;
123 bool OutputSurface::ForcedDrawToSoftwareDevice() const { return false; }
125 bool OutputSurface::BindToClient(OutputSurfaceClient* client) {
130 if (context_provider_) {
131 success = context_provider_->BindToCurrentThread();
142 bool OutputSurface::InitializeAndSetContext3d(
143 scoped_refptr<ContextProvider> context_provider) {
144 DCHECK(!context_provider_);
145 DCHECK(context_provider);
148 bool success = false;
149 if (context_provider->BindToCurrentThread()) {
150 context_provider_ = context_provider;
152 client_->DeferredInitialize();
162 void OutputSurface::ReleaseGL() {
164 DCHECK(context_provider_);
165 client_->ReleaseGL();
169 void OutputSurface::SetUpContext3d() {
170 DCHECK(context_provider_);
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)));
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);
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);
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());
203 context_provider_ = NULL;
206 void OutputSurface::EnsureBackbuffer() {
207 if (software_device_)
208 software_device_->EnsureBackbuffer();
211 void OutputSurface::DiscardBackbuffer() {
212 if (context_provider_)
213 context_provider_->ContextGL()->DiscardBackbufferCHROMIUM();
214 if (software_device_)
215 software_device_->DiscardBackbuffer();
218 void OutputSurface::Reshape(const gfx::Size& size, float scale_factor) {
219 if (size == surface_size_ && scale_factor == device_scale_factor_)
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);
228 if (software_device_)
229 software_device_->Resize(size);
232 gfx::Size OutputSurface::SurfaceSize() const {
233 return surface_size_;
236 void OutputSurface::BindFramebuffer() {
237 DCHECK(context_provider_);
238 context_provider_->ContextGL()->BindFramebuffer(GL_FRAMEBUFFER, 0);
241 void OutputSurface::SwapBuffers(CompositorFrame* frame) {
242 if (frame->software_frame_data) {
243 PostSwapBuffersComplete();
244 client_->DidSwapBuffers();
248 DCHECK(context_provider_);
249 DCHECK(frame->gl_frame_data);
251 UpdateAndMeasureGpuLatency();
252 if (frame->gl_frame_data->sub_buffer_rect ==
253 gfx::Rect(frame->gl_frame_data->size)) {
254 context_provider_->ContextSupport()->Swap();
256 context_provider_->ContextSupport()->PartialSwapBuffers(
257 frame->gl_frame_data->sub_buffer_rect);
260 client_->DidSwapBuffers();
263 base::TimeDelta OutputSurface::GpuLatencyEstimate() {
264 if (context_provider_ && !capabilities_.adjust_deadline_for_parent)
265 return gpu_latency_history_.Percentile(kGpuLatencyEstimationPercentile);
267 return base::TimeDelta();
270 void OutputSurface::UpdateAndMeasureGpuLatency() {
271 // http://crbug.com/306690 tracks re-enabling latency queries.
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)
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);
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);
294 base::TimeDelta latency = base::TimeDelta::FromMicroseconds(value);
295 base::TimeDelta latency_estimate = GpuLatencyEstimate();
296 gpu_latency_history_.InsertSample(latency);
298 base::TimeDelta latency_overestimate;
299 base::TimeDelta latency_underestimate;
300 if (latency > latency_estimate)
301 latency_underestimate = latency - latency_estimate;
303 latency_overestimate = latency_estimate - latency;
304 UMA_HISTOGRAM_CUSTOM_TIMES("Renderer.GpuLatency",
306 base::TimeDelta::FromMilliseconds(1),
307 base::TimeDelta::FromMilliseconds(100),
309 UMA_HISTOGRAM_CUSTOM_TIMES("Renderer.GpuLatencyUnderestimate",
310 latency_underestimate,
311 base::TimeDelta::FromMilliseconds(1),
312 base::TimeDelta::FromMilliseconds(100),
314 UMA_HISTOGRAM_CUSTOM_TIMES("Renderer.GpuLatencyOverestimate",
315 latency_overestimate,
316 base::TimeDelta::FromMilliseconds(1),
317 base::TimeDelta::FromMilliseconds(100),
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();
326 context_provider_->ContextGL()->GenQueriesEXT(1, &gpu_latency_query_id);
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);
336 void OutputSurface::PostSwapBuffersComplete() {
337 base::MessageLoop::current()->PostTask(
339 base::Bind(&OutputSurface::OnSwapBuffersComplete,
340 weak_ptr_factory_.GetWeakPtr()));
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();
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);