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
)
47 : context_provider_(context_provider
),
48 device_scale_factor_(-1),
49 max_frames_pending_(0),
50 pending_swap_buffers_(0),
51 needs_begin_impl_frame_(false),
52 client_ready_for_begin_impl_frame_(true),
54 check_for_retroactive_begin_impl_frame_pending_(false),
55 external_stencil_test_enabled_(false),
56 weak_ptr_factory_(this),
57 gpu_latency_history_(kGpuLatencyHistorySize
) {}
59 OutputSurface::OutputSurface(scoped_ptr
<SoftwareOutputDevice
> software_device
)
60 : software_device_(software_device
.Pass()),
61 device_scale_factor_(-1),
62 max_frames_pending_(0),
63 pending_swap_buffers_(0),
64 needs_begin_impl_frame_(false),
65 client_ready_for_begin_impl_frame_(true),
67 check_for_retroactive_begin_impl_frame_pending_(false),
68 external_stencil_test_enabled_(false),
69 weak_ptr_factory_(this),
70 gpu_latency_history_(kGpuLatencyHistorySize
) {}
72 OutputSurface::OutputSurface(scoped_refptr
<ContextProvider
> context_provider
,
73 scoped_ptr
<SoftwareOutputDevice
> software_device
)
74 : context_provider_(context_provider
),
75 software_device_(software_device
.Pass()),
76 device_scale_factor_(-1),
77 max_frames_pending_(0),
78 pending_swap_buffers_(0),
79 needs_begin_impl_frame_(false),
80 client_ready_for_begin_impl_frame_(true),
82 check_for_retroactive_begin_impl_frame_pending_(false),
83 external_stencil_test_enabled_(false),
84 weak_ptr_factory_(this),
85 gpu_latency_history_(kGpuLatencyHistorySize
) {}
87 void OutputSurface::InitializeBeginImplFrameEmulation(
88 base::SingleThreadTaskRunner
* task_runner
,
89 bool throttle_frame_production
,
90 base::TimeDelta interval
) {
91 if (throttle_frame_production
) {
92 scoped_refptr
<DelayBasedTimeSource
> time_source
;
93 if (gfx::FrameTime::TimestampsAreHighRes())
94 time_source
= DelayBasedTimeSourceHighRes::Create(interval
, task_runner
);
96 time_source
= DelayBasedTimeSource::Create(interval
, task_runner
);
97 frame_rate_controller_
.reset(new FrameRateController(time_source
));
99 frame_rate_controller_
.reset(new FrameRateController(task_runner
));
102 frame_rate_controller_
->SetClient(this);
103 frame_rate_controller_
->SetMaxSwapsPending(max_frames_pending_
);
104 frame_rate_controller_
->SetDeadlineAdjustment(
105 capabilities_
.adjust_deadline_for_parent
?
106 BeginFrameArgs::DefaultDeadlineAdjustment() : base::TimeDelta());
108 // The new frame rate controller will consume the swap acks of the old
109 // frame rate controller, so we set that expectation up here.
110 for (int i
= 0; i
< pending_swap_buffers_
; i
++)
111 frame_rate_controller_
->DidSwapBuffers();
114 void OutputSurface::SetMaxFramesPending(int max_frames_pending
) {
115 if (frame_rate_controller_
)
116 frame_rate_controller_
->SetMaxSwapsPending(max_frames_pending
);
117 max_frames_pending_
= max_frames_pending
;
120 void OutputSurface::OnVSyncParametersChanged(base::TimeTicks timebase
,
121 base::TimeDelta interval
) {
122 TRACE_EVENT2("cc", "OutputSurface::OnVSyncParametersChanged",
123 "timebase", (timebase
- base::TimeTicks()).InSecondsF(),
124 "interval", interval
.InSecondsF());
125 if (frame_rate_controller_
)
126 frame_rate_controller_
->SetTimebaseAndInterval(timebase
, interval
);
129 void OutputSurface::FrameRateControllerTick(bool throttled
,
130 const BeginFrameArgs
& args
) {
131 DCHECK(frame_rate_controller_
);
133 skipped_begin_impl_frame_args_
= args
;
135 BeginImplFrame(args
);
138 // Forwarded to OutputSurfaceClient
139 void OutputSurface::SetNeedsRedrawRect(const gfx::Rect
& damage_rect
) {
140 TRACE_EVENT0("cc", "OutputSurface::SetNeedsRedrawRect");
141 client_
->SetNeedsRedrawRect(damage_rect
);
144 void OutputSurface::SetNeedsBeginImplFrame(bool enable
) {
145 TRACE_EVENT1("cc", "OutputSurface::SetNeedsBeginImplFrame", "enable", enable
);
146 needs_begin_impl_frame_
= enable
;
147 client_ready_for_begin_impl_frame_
= true;
148 if (frame_rate_controller_
) {
149 BeginFrameArgs skipped
= frame_rate_controller_
->SetActive(enable
);
150 if (skipped
.IsValid())
151 skipped_begin_impl_frame_args_
= skipped
;
153 if (needs_begin_impl_frame_
)
154 PostCheckForRetroactiveBeginImplFrame();
157 void OutputSurface::BeginImplFrame(const BeginFrameArgs
& args
) {
158 TRACE_EVENT2("cc", "OutputSurface::BeginImplFrame",
159 "client_ready_for_begin_impl_frame_",
160 client_ready_for_begin_impl_frame_
,
161 "pending_swap_buffers_", pending_swap_buffers_
);
162 if (!needs_begin_impl_frame_
|| !client_ready_for_begin_impl_frame_
||
163 (pending_swap_buffers_
>= max_frames_pending_
&&
164 max_frames_pending_
> 0)) {
165 skipped_begin_impl_frame_args_
= args
;
167 client_ready_for_begin_impl_frame_
= false;
168 client_
->BeginImplFrame(args
);
169 // args might be an alias for skipped_begin_impl_frame_args_.
170 // Do not reset it before calling BeginImplFrame!
171 skipped_begin_impl_frame_args_
= BeginFrameArgs();
175 base::TimeTicks
OutputSurface::RetroactiveBeginImplFrameDeadline() {
176 // TODO(brianderson): Remove the alternative deadline once we have better
177 // deadline estimations.
178 base::TimeTicks alternative_deadline
=
179 skipped_begin_impl_frame_args_
.frame_time
+
180 BeginFrameArgs::DefaultRetroactiveBeginFramePeriod();
181 return std::max(skipped_begin_impl_frame_args_
.deadline
,
182 alternative_deadline
);
185 void OutputSurface::PostCheckForRetroactiveBeginImplFrame() {
186 if (!skipped_begin_impl_frame_args_
.IsValid() ||
187 check_for_retroactive_begin_impl_frame_pending_
)
190 base::MessageLoop::current()->PostTask(
192 base::Bind(&OutputSurface::CheckForRetroactiveBeginImplFrame
,
193 weak_ptr_factory_
.GetWeakPtr()));
194 check_for_retroactive_begin_impl_frame_pending_
= true;
197 void OutputSurface::CheckForRetroactiveBeginImplFrame() {
198 TRACE_EVENT0("cc", "OutputSurface::CheckForRetroactiveBeginImplFrame");
199 check_for_retroactive_begin_impl_frame_pending_
= false;
200 if (gfx::FrameTime::Now() < RetroactiveBeginImplFrameDeadline())
201 BeginImplFrame(skipped_begin_impl_frame_args_
);
204 void OutputSurface::DidSwapBuffers() {
205 pending_swap_buffers_
++;
206 TRACE_EVENT1("cc", "OutputSurface::DidSwapBuffers",
207 "pending_swap_buffers_", pending_swap_buffers_
);
208 client_
->DidSwapBuffers();
209 if (frame_rate_controller_
)
210 frame_rate_controller_
->DidSwapBuffers();
211 PostCheckForRetroactiveBeginImplFrame();
214 void OutputSurface::OnSwapBuffersComplete() {
215 pending_swap_buffers_
--;
216 TRACE_EVENT1("cc", "OutputSurface::OnSwapBuffersComplete",
217 "pending_swap_buffers_", pending_swap_buffers_
);
218 client_
->OnSwapBuffersComplete();
219 if (frame_rate_controller_
)
220 frame_rate_controller_
->DidSwapBuffersComplete();
221 PostCheckForRetroactiveBeginImplFrame();
224 void OutputSurface::ReclaimResources(const CompositorFrameAck
* ack
) {
225 client_
->ReclaimResources(ack
);
228 void OutputSurface::DidLoseOutputSurface() {
229 TRACE_EVENT0("cc", "OutputSurface::DidLoseOutputSurface");
230 client_ready_for_begin_impl_frame_
= true;
231 pending_swap_buffers_
= 0;
232 skipped_begin_impl_frame_args_
= BeginFrameArgs();
233 if (frame_rate_controller_
)
234 frame_rate_controller_
->SetActive(false);
235 pending_gpu_latency_query_ids_
.clear();
236 available_gpu_latency_query_ids_
.clear();
237 client_
->DidLoseOutputSurface();
240 void OutputSurface::SetExternalStencilTest(bool enabled
) {
241 external_stencil_test_enabled_
= enabled
;
244 void OutputSurface::SetExternalDrawConstraints(const gfx::Transform
& transform
,
245 const gfx::Rect
& viewport
,
246 const gfx::Rect
& clip
,
247 bool valid_for_tile_management
) {
248 client_
->SetExternalDrawConstraints(
249 transform
, viewport
, clip
, valid_for_tile_management
);
252 OutputSurface::~OutputSurface() {
253 if (frame_rate_controller_
)
254 frame_rate_controller_
->SetActive(false);
258 bool OutputSurface::HasExternalStencilTest() const {
259 return external_stencil_test_enabled_
;
262 bool OutputSurface::ForcedDrawToSoftwareDevice() const { return false; }
264 bool OutputSurface::BindToClient(OutputSurfaceClient
* client
) {
269 if (context_provider_
) {
270 success
= context_provider_
->BindToCurrentThread();
281 bool OutputSurface::InitializeAndSetContext3d(
282 scoped_refptr
<ContextProvider
> context_provider
,
283 scoped_refptr
<ContextProvider
> offscreen_context_provider
) {
284 DCHECK(!context_provider_
);
285 DCHECK(context_provider
);
288 bool success
= false;
289 if (context_provider
->BindToCurrentThread()) {
290 context_provider_
= context_provider
;
292 if (client_
->DeferredInitialize(offscreen_context_provider
))
302 void OutputSurface::ReleaseGL() {
304 DCHECK(context_provider_
);
305 client_
->ReleaseGL();
309 void OutputSurface::SetUpContext3d() {
310 DCHECK(context_provider_
);
313 context_provider_
->SetLostContextCallback(
314 base::Bind(&OutputSurface::DidLoseOutputSurface
,
315 base::Unretained(this)));
316 context_provider_
->ContextSupport()->SetSwapBuffersCompleteCallback(
317 base::Bind(&OutputSurface::OnSwapBuffersComplete
,
318 base::Unretained(this)));
319 context_provider_
->SetMemoryPolicyChangedCallback(
320 base::Bind(&OutputSurface::SetMemoryPolicy
,
321 base::Unretained(this)));
324 void OutputSurface::ResetContext3d() {
325 if (context_provider_
.get()) {
326 while (!pending_gpu_latency_query_ids_
.empty()) {
327 unsigned query_id
= pending_gpu_latency_query_ids_
.front();
328 pending_gpu_latency_query_ids_
.pop_front();
329 context_provider_
->ContextGL()->DeleteQueriesEXT(1, &query_id
);
331 while (!available_gpu_latency_query_ids_
.empty()) {
332 unsigned query_id
= available_gpu_latency_query_ids_
.front();
333 available_gpu_latency_query_ids_
.pop_front();
334 context_provider_
->ContextGL()->DeleteQueriesEXT(1, &query_id
);
336 context_provider_
->SetLostContextCallback(
337 ContextProvider::LostContextCallback());
338 context_provider_
->SetMemoryPolicyChangedCallback(
339 ContextProvider::MemoryPolicyChangedCallback());
340 if (gpu::ContextSupport
* support
= context_provider_
->ContextSupport())
341 support
->SetSwapBuffersCompleteCallback(base::Closure());
343 context_provider_
= NULL
;
346 void OutputSurface::EnsureBackbuffer() {
347 if (software_device_
)
348 software_device_
->EnsureBackbuffer();
351 void OutputSurface::DiscardBackbuffer() {
352 if (context_provider_
)
353 context_provider_
->ContextGL()->DiscardBackbufferCHROMIUM();
354 if (software_device_
)
355 software_device_
->DiscardBackbuffer();
358 void OutputSurface::Reshape(gfx::Size size
, float scale_factor
) {
359 if (size
== surface_size_
&& scale_factor
== device_scale_factor_
)
362 surface_size_
= size
;
363 device_scale_factor_
= scale_factor
;
364 if (context_provider_
) {
365 context_provider_
->ContextGL()->ResizeCHROMIUM(
366 size
.width(), size
.height(), scale_factor
);
368 if (software_device_
)
369 software_device_
->Resize(size
);
372 gfx::Size
OutputSurface::SurfaceSize() const {
373 return surface_size_
;
376 void OutputSurface::BindFramebuffer() {
377 DCHECK(context_provider_
);
378 context_provider_
->ContextGL()->BindFramebuffer(GL_FRAMEBUFFER
, 0);
381 void OutputSurface::SwapBuffers(CompositorFrame
* frame
) {
382 if (frame
->software_frame_data
) {
383 PostSwapBuffersComplete();
388 DCHECK(context_provider_
);
389 DCHECK(frame
->gl_frame_data
);
391 UpdateAndMeasureGpuLatency();
392 if (frame
->gl_frame_data
->sub_buffer_rect
==
393 gfx::Rect(frame
->gl_frame_data
->size
)) {
394 context_provider_
->ContextSupport()->Swap();
396 context_provider_
->ContextSupport()->PartialSwapBuffers(
397 frame
->gl_frame_data
->sub_buffer_rect
);
403 base::TimeDelta
OutputSurface::GpuLatencyEstimate() {
404 if (context_provider_
&& !capabilities_
.adjust_deadline_for_parent
)
405 return gpu_latency_history_
.Percentile(kGpuLatencyEstimationPercentile
);
407 return base::TimeDelta();
410 void OutputSurface::UpdateAndMeasureGpuLatency() {
411 return; // http://crbug.com/306690 tracks re-enabling latency queries.
413 // We only care about GPU latency for surfaces that do not have a parent
414 // compositor, since surfaces that do have a parent compositor can use
415 // mailboxes or delegated rendering to send frames to their parent without
416 // incurring GPU latency.
417 if (capabilities_
.adjust_deadline_for_parent
)
420 while (pending_gpu_latency_query_ids_
.size()) {
421 unsigned query_id
= pending_gpu_latency_query_ids_
.front();
422 unsigned query_complete
= 1;
423 context_provider_
->ContextGL()->GetQueryObjectuivEXT(
424 query_id
, GL_QUERY_RESULT_AVAILABLE_EXT
, &query_complete
);
429 context_provider_
->ContextGL()->GetQueryObjectuivEXT(
430 query_id
, GL_QUERY_RESULT_EXT
, &value
);
431 pending_gpu_latency_query_ids_
.pop_front();
432 available_gpu_latency_query_ids_
.push_back(query_id
);
434 base::TimeDelta latency
= base::TimeDelta::FromMicroseconds(value
);
435 base::TimeDelta latency_estimate
= GpuLatencyEstimate();
436 gpu_latency_history_
.InsertSample(latency
);
438 base::TimeDelta latency_overestimate
;
439 base::TimeDelta latency_underestimate
;
440 if (latency
> latency_estimate
)
441 latency_underestimate
= latency
- latency_estimate
;
443 latency_overestimate
= latency_estimate
- latency
;
444 UMA_HISTOGRAM_CUSTOM_TIMES("Renderer.GpuLatency",
446 base::TimeDelta::FromMilliseconds(1),
447 base::TimeDelta::FromMilliseconds(100),
449 UMA_HISTOGRAM_CUSTOM_TIMES("Renderer.GpuLatencyUnderestimate",
450 latency_underestimate
,
451 base::TimeDelta::FromMilliseconds(1),
452 base::TimeDelta::FromMilliseconds(100),
454 UMA_HISTOGRAM_CUSTOM_TIMES("Renderer.GpuLatencyOverestimate",
455 latency_overestimate
,
456 base::TimeDelta::FromMilliseconds(1),
457 base::TimeDelta::FromMilliseconds(100),
461 unsigned gpu_latency_query_id
;
462 if (available_gpu_latency_query_ids_
.size()) {
463 gpu_latency_query_id
= available_gpu_latency_query_ids_
.front();
464 available_gpu_latency_query_ids_
.pop_front();
466 context_provider_
->ContextGL()->GenQueriesEXT(1, &gpu_latency_query_id
);
469 context_provider_
->ContextGL()->BeginQueryEXT(GL_LATENCY_QUERY_CHROMIUM
,
470 gpu_latency_query_id
);
471 context_provider_
->ContextGL()->EndQueryEXT(GL_LATENCY_QUERY_CHROMIUM
);
472 pending_gpu_latency_query_ids_
.push_back(gpu_latency_query_id
);
475 void OutputSurface::PostSwapBuffersComplete() {
476 base::MessageLoop::current()->PostTask(
478 base::Bind(&OutputSurface::OnSwapBuffersComplete
,
479 weak_ptr_factory_
.GetWeakPtr()));
482 void OutputSurface::SetMemoryPolicy(const ManagedMemoryPolicy
& policy
) {
483 TRACE_EVENT1("cc", "OutputSurface::SetMemoryPolicy",
484 "bytes_limit_when_visible", policy
.bytes_limit_when_visible
);
485 // Just ignore the memory manager when it says to set the limit to zero
486 // bytes. This will happen when the memory manager thinks that the renderer
487 // is not visible (which the renderer knows better).
488 if (policy
.bytes_limit_when_visible
)
489 client_
->SetMemoryPolicy(policy
);